Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 26 additions & 12 deletions examples/can_simple.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,29 @@
"""
Minimal example for controlling an ODrive via the CANSimple protocol.

Puts the ODrive into closed loop control mode, sends a velocity setpoint of 1.0
and then prints the encoder feedback.
Puts the ODrive into closed loop control mode, sends periodic sinusoidal velocity
setpoints, and asynchronously prints the encoder feedback.

Assumes that the ODrive is already configured for velocity control.

If the watchdog is enabled on the ODrive, it is fed implicitly by the continuous
velocity setpoint message and the motor will stop when the script is terminated.
The heartbeat interval should be shorter than the watchdog timeout to ensure
timely confirmation of the axis entering closed loop control mode without
triggering the watchdog.

See https://docs.odriverobotics.com/v/latest/manual/can-protocol.html for protocol
documentation.
"""

import can
import math
import time
import struct

node_id = 0 # must match `<odrv>.axis0.config.can.node_id`. The default is 0.

bus = can.interface.Bus("can0", bustype="socketcan")
bus = can.interface.Bus("can0", interface="socketcan")

# Flush CAN RX buffer so there are no more old pending messages
while not (bus.recv(timeout=0) is None): pass
Expand All @@ -34,15 +42,21 @@
if state == 8: # 8: AxisState.CLOSED_LOOP_CONTROL
break

# Set velocity to 1.0 turns/s
bus.send(can.Message(
arbitration_id=(node_id << 5 | 0x0d), # 0x0d: Set_Input_Vel
data=struct.pack('<ff', 1.0, 0.0), # 1.0: velocity, 0.0: torque feedforward
is_extended_id=False
))

# Print encoder feedback
for msg in bus:
# Handler for incoming CAN messages to print encoder feedback
def on_rx_message(msg: can.Message):
if msg.arbitration_id == (node_id << 5 | 0x09): # 0x09: Get_Encoder_Estimates
pos, vel = struct.unpack('<ff', bytes(msg.data))
print(f"pos: {pos:.3f} [turns], vel: {vel:.3f} [turns/s]")

# Control ODrive while notifier object exist
with can.Notifier(bus, [on_rx_message]):
while True:
velocity_setpoint = math.sin(2 * math.pi * 0.5 * time.monotonic()) # turns / s

# Update velocity and reset watchdog timer
bus.send(can.Message(
arbitration_id=(node_id << 5 | 0x0d), # 0x0d: Set_Input_Vel
data=struct.pack('<ff', velocity_setpoint, 0.0), # 0.0: torque feedforward
is_extended_id=False
))
time.sleep(0.1)