Skip to content
Open
Show file tree
Hide file tree
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
61 changes: 43 additions & 18 deletions tools/can_dbc_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@
# bus = can.Bus("vcan0", bustype="virtual")
bus = can.Bus("can0", bustype="socketcan")
axisID = 0x1

axis="Axis1"
print("\nRequesting AXIS_STATE_FULL_CALIBRATION_SEQUENCE (0x03) on axisID: " + str(axisID))
msg = db.get_message_by_name('Set_Axis_State')
msg = db.get_message_by_name(f'{axis}_Set_Axis_State')
data = msg.encode({'Axis_Requested_State': 0x03})
msg = can.Message(arbitration_id=msg.frame_id | axisID << 5, is_extended_id=False, data=data)
print(db.decode_message('Set_Axis_State', msg.data))
print(db.decode_message(f'{axis}_Set_Axis_State', msg.data))
print(msg)

try:
Expand All @@ -27,23 +27,24 @@
# Read messages infinitely and wait for the right ID to show up
while True:
msg = bus.recv()
if msg.arbitration_id == ((axisID << 5) | db.get_message_by_name('Heartbeat').frame_id):
current_state = db.decode_message('Heartbeat', msg.data)['Axis_State']
if current_state == 0x1:
if msg.arbitration_id == ((axisID << 5) | db.get_message_by_name(f'{axis}_Heartbeat').frame_id):
current_state = db.decode_message(f'{axis}_Heartbeat', msg.data)['Axis_State']
if current_state == 'IDLE':
print("\nAxis has returned to Idle state.")
break

for msg in bus:
if msg.arbitration_id == ((axisID << 5) | db.get_message_by_name('Heartbeat').frame_id):
errorCode = db.decode_message('Heartbeat', msg.data)['Axis_Error']
if errorCode == 0x00:
if msg.arbitration_id == ((axisID << 5) | db.get_message_by_name(f'{axis}_Heartbeat').frame_id):
errorCode = db.decode_message(f'{axis}_Heartbeat', msg.data)['Axis_Error']
print(errorCode)
if errorCode == 'NONE':
print("No errors")
else:
print("Axis error! Error code: "+str(hex(errorCode)))
break

print("\nPutting axis",axisID,"into AXIS_STATE_CLOSED_LOOP_CONTROL (0x08)...")
data = db.encode_message('Set_Axis_State', {'Axis_Requested_State': 0x08})
data = db.encode_message(f'{axis}_Set_Axis_State', {'Axis_Requested_State': 0x08})
msg = can.Message(arbitration_id=0x07 | axisID << 5, is_extended_id=False, data=data)
print(msg)

Expand All @@ -56,7 +57,7 @@
for msg in bus:
if msg.arbitration_id == 0x01 | axisID << 5:
print("\nReceived Axis heartbeat message:")
msg = db.decode_message('Heartbeat', msg.data)
msg = db.decode_message(f'{axis}_Heartbeat', msg.data)
print(msg)
if msg['Axis_State'] == 0x8:
print("Axis has entered closed loop")
Expand All @@ -66,15 +67,39 @@

target = 0

data = db.encode_message('Set_Limits', {'Velocity_Limit':10.0, 'Current_Limit':10.0})
data = db.encode_message(f'{axis}_Set_Limits', {'Velocity_Limit':10.0, 'Current_Limit':10.0})
msg = can.Message(arbitration_id=axisID << 5 | 0x00F, is_extended_id=False, data=data)
bus.send(msg)

t0 = time.monotonic()
print("\nSweeping velocity between -4 and 4.\nCTRL+C to stop\n")
time.sleep(2)
i = 0
while True:
setpoint = 4.0 * math.sin((time.monotonic() - t0)*2)
print("goto " + str(setpoint))
data = db.encode_message('Set_Input_Pos', {'Input_Pos':setpoint, 'Vel_FF':0.0, 'Torque_FF':0.0})
msg = can.Message(arbitration_id=axisID << 5 | 0x00C, data=data, is_extended_id=False)
bus.send(msg)
time.sleep(0.01)
try:
setpoint = 4.0 * math.sin((time.monotonic() - t0)*2)
# Don't spam the terminal
if (i % 25 == 0):
print(f"Velocity: {round(setpoint,2)}")
i = 0
data = db.encode_message(f'{axis}_Set_Input_Pos', {'Input_Pos':setpoint, 'Vel_FF':setpoint, 'Torque_FF':0.0})
msg = can.Message(arbitration_id=axisID << 5 | 0x00C, data=data, is_extended_id=False)
bus.send(msg)
i+=1
time.sleep(0.01)
except KeyboardInterrupt:
break
print("\nDone! Setting to AXIS_STATE_IDLE")
data = db.encode_message(f'{axis}_Set_Axis_State', {'Axis_Requested_State': 0x01})
msg = can.Message(arbitration_id=axisID << 5 | 0x07, is_extended_id=False, data=data)
time.sleep(0.5)
bus.send(msg)
while True:
for msg in bus:
if msg.arbitration_id == 0x01 | axisID << 5:
current_state = db.decode_message(f'{axis}_Heartbeat', msg.data)['Axis_State']
print(current_state)
if current_state == 'IDLE':
print("\nAxis has returned to Idle state.")
break
break
68 changes: 35 additions & 33 deletions tools/create_can_dbc.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
from cantools.database import *
from odrive.enums import *
from cantools.database.conversion import NamedSignalConversion

msgList = []
nodes = [can.Node('Master')]
buses = [can.Bus('ODrive', None, 100000)]


for axisID in range(0, 8):
newNode = can.Node(f"ODrive_Axis{axisID}")
nodes.append(newNode)

# 0x00 - NMT Message (Reserved)

# 0x001 - Heartbeat
axisError = can.Signal("Axis_Error", 0, 32, receivers=['Master'], choices={error.value: error.name for error in AxisError})
axisState = can.Signal("Axis_State", 32, 8, receivers=['Master'], choices={state.value: state.name for state in AxisState})
axisError = can.Signal("Axis_Error", 0, 32, receivers=['Master'], conversion=NamedSignalConversion(scale=1,offset=0, is_float=False, choices={error.value: error.name for error in AxisError}))
axisState = can.Signal("Axis_State", 32, 8, receivers=['Master'], conversion=NamedSignalConversion(scale=1,offset=0,is_float=False,choices={state.value: state.name for state in AxisState}))
motorErrorFlag = can.Signal("Motor_Error_Flag", 40, 1, receivers=['Master'])
encoderErrorFlag = can.Signal("Encoder_Error_Flag", 48, 1, receivers=['Master'])
controllerErrorFlag = can.Signal("Controller_Error_Flag", 56, 1, receivers=['Master'])
Expand All @@ -35,17 +37,17 @@
estopMsg = can.Message(0x002, "Estop", 0, [], senders=['Master'])

# 0x003 - Motor Error
motorError = can.Signal("Motor_Error", 0, 32, receivers=['Master'], choices={error.value: error.name for error in MotorError})
motorError = can.Signal("Motor_Error", 0, 32, receivers=['Master'], conversion=NamedSignalConversion(scale=1,offset=0,is_float=False,choices={error.value: error.name for error in MotorError}))
motorErrorMsg = can.Message(0x003, "Get_Motor_Error", 8, [motorError], senders=[newNode.name])

# 0x004 - Encoder Error
encoderError = can.Signal("Encoder_Error", 0, 32, receivers=['Master'], choices={error.value: error.name for error in EncoderError})
encoderError = can.Signal("Encoder_Error", 0, 32, receivers=['Master'], conversion=NamedSignalConversion(scale=1,offset=0,is_float=False,choices={error.value: error.name for error in EncoderError}))
encoderErrorMsg = can.Message(
0x004, "Get_Encoder_Error", 8, [encoderError], senders=[newNode.name]
)

# 0x005 - Sensorless Error
sensorlessError = can.Signal("Sensorless_Error", 0, 32, receivers=['Master'], choices={error.value: error.name for error in SensorlessEstimatorError})
sensorlessError = can.Signal("Sensorless_Error", 0, 32, receivers=['Master'], conversion=NamedSignalConversion(scale=1,offset=0,is_float=False,choices={error.value: error.name for error in SensorlessEstimatorError}))
sensorlessErrorMsg = can.Message(
0x005, "Get_Sensorless_Error", 8, [sensorlessError], senders=[newNode.name]
)
Expand All @@ -55,16 +57,16 @@
axisNodeMsg = can.Message(0x006, "Set_Axis_Node_ID", 8, [axisNodeID], senders=['Master'])

# 0x007 - Requested State
axisRequestedState = can.Signal("Axis_Requested_State", 0, 32, receivers=[newNode.name], choices={state.value: state.name for state in AxisState})
axisRequestedState = can.Signal("Axis_Requested_State", 0, 32, receivers=[newNode.name], conversion=NamedSignalConversion(scale=1,offset=0,is_float=False,choices={state.value: state.name for state in AxisState}))
setAxisState = can.Message(
0x007, "Set_Axis_State", 8, [axisRequestedState], senders=['Master']
)

# 0x008 - Startup Config (Reserved)

# 0x009 - Encoder Estimates
encoderPosEstimate = can.Signal("Pos_Estimate", 0, 32, is_float=True, receivers=['Master'], unit='rev')
encoderVelEstimate = can.Signal("Vel_Estimate", 32, 32, is_float=True, receivers=['Master'], unit='rev/s')
encoderPosEstimate = can.Signal("Pos_Estimate", 0, 32, conversion=NamedSignalConversion(scale=1,offset=0,is_float=True,choices={}), receivers=['Master'], unit='rev')
encoderVelEstimate = can.Signal("Vel_Estimate", 32, 32, conversion=NamedSignalConversion(scale=1,offset=0,is_float=True,choices={}), receivers=['Master'], unit='rev/s')
encoderEstimates = can.Message(
0x009, "Get_Encoder_Estimates", 8, [encoderPosEstimate, encoderVelEstimate], senders=[newNode.name], send_type='cyclic', cycle_time=10
)
Expand All @@ -77,36 +79,36 @@
)

# 0x00B - Set Controller Modes
controlMode = can.Signal("Control_Mode", 0, 32, receivers=[newNode.name], choices={state.value: state.name for state in ControlMode})
inputMode = can.Signal("Input_Mode", 32, 32, receivers=[newNode.name], choices={state.value: state.name for state in InputMode})
controlMode = can.Signal("Control_Mode", 0, 32, receivers=[newNode.name], conversion=NamedSignalConversion(scale=1,offset=0,is_float=False,choices={state.value: state.name for state in ControlMode}))
inputMode = can.Signal("Input_Mode", 32, 32, receivers=[newNode.name], conversion=NamedSignalConversion(scale=1,offset=0,is_float=False,choices={state.value: state.name for state in InputMode}))
setControllerModeMsg = can.Message(
0x00B, "Set_Controller_Mode", 8, [controlMode, inputMode], senders=['Master']
)

# 0x00C - Set Input Pos
inputPos = can.Signal("Input_Pos", 0, 32, is_float=True, receivers=[newNode.name], unit='rev')
velFF = can.Signal("Vel_FF", 32, 16, is_signed=True, scale=0.001, receivers=[newNode.name], unit='rev/s')
torqueFF = can.Signal("Torque_FF", 48, 16, is_signed=True, scale=0.001, receivers=[newNode.name], unit='Nm')
inputPos = can.Signal("Input_Pos", 0, 32, conversion=NamedSignalConversion(scale=1,offset=0,is_float=True,choices={}), receivers=[newNode.name], unit='rev')
velFF = can.Signal("Vel_FF", 32, 16, is_signed=True, conversion=NamedSignalConversion(scale=0.001,offset=0,is_float=False,choices={}), receivers=[newNode.name], unit='rev/s')
torqueFF = can.Signal("Torque_FF", 48, 16, is_signed=True, conversion=NamedSignalConversion(scale=.001,offset=0,is_float=False,choices={}), receivers=[newNode.name], unit='Nm')
setInputPosMsg = can.Message(
0x00C, "Set_Input_Pos", 8, [inputPos, velFF, torqueFF], senders=['Master']
)

# 0x00D - Set Input Vel
inputVel = can.Signal("Input_Vel", 0, 32, is_float=True, receivers=[newNode.name], unit='rev')
inputTorqueFF = can.Signal("Input_Torque_FF", 32, 32, is_float=True, receivers=[newNode.name], unit='rev/s')
inputVel = can.Signal("Input_Vel", 0, 32, conversion=NamedSignalConversion(scale=1,offset=0,is_float=True,choices={}), receivers=[newNode.name], unit='rev')
inputTorqueFF = can.Signal("Input_Torque_FF", 32, 32, conversion=NamedSignalConversion(scale=1,offset=0,is_float=True,choices={}), receivers=[newNode.name], unit='rev/s')
setInputVelMsg = can.Message(
0x00D, "Set_Input_Vel", 8, [inputVel, inputTorqueFF], senders=['Master']
)

# 0x00E - Set Input Torque
inputTorque = can.Signal("Input_Torque", 0, 32, is_float=True, receivers=[newNode.name], unit='Nm')
inputTorque = can.Signal("Input_Torque", 0, 32, conversion=NamedSignalConversion(scale=1,offset=0,is_float=True,choices={}), receivers=[newNode.name], unit='Nm')
setInputTqMsg = can.Message(
0x00E, "Set_Input_Torque", 8, [inputTorque], senders=['Master']
)

# 0x00F - Set Velocity Limit
velLimit = can.Signal("Velocity_Limit", 0, 32, is_float=True, receivers=[newNode.name], unit='rev/s')
currentLimit = can.Signal("Current_Limit", 32, 32, is_float=True, receivers=[newNode.name], unit='A')
velLimit = can.Signal("Velocity_Limit", 0, 32, conversion=NamedSignalConversion(scale=1,offset=0,is_float=True,choices={}), receivers=[newNode.name], unit='rev/s')
currentLimit = can.Signal("Current_Limit", 32, 32, conversion=NamedSignalConversion(scale=1,offset=0,is_float=True,choices={}), receivers=[newNode.name], unit='A')
setVelLimMsg = can.Message(
0x00F, "Set_Limits", 8, [velLimit, currentLimit], senders=['Master']
)
Expand All @@ -115,40 +117,40 @@
startAnticoggingMsg = can.Message(0x010, "Start_Anticogging", 0, [], senders=['Master'])

# 0x011 - Set Traj Vel Limit
trajVelLim = can.Signal("Traj_Vel_Limit", 0, 32, is_float=True, receivers=[newNode.name], unit='rev/s')
trajVelLim = can.Signal("Traj_Vel_Limit", 0, 32, conversion=NamedSignalConversion(scale=1,offset=0,is_float=True,choices={}), receivers=[newNode.name], unit='rev/s')
setTrajVelMsg = can.Message(
0x011, "Set_Traj_Vel_Limit", 8, [trajVelLim], senders=['Master']
)

# 0x012 - Set Traj Accel Limits
trajAccelLim = can.Signal("Traj_Accel_Limit", 0, 32, is_float=True, receivers=[newNode.name], unit='rev/s^2')
trajDecelLim = can.Signal("Traj_Decel_Limit", 32, 32, is_float=True, receivers=[newNode.name], unit='rev/s^2')
trajAccelLim = can.Signal("Traj_Accel_Limit", 0, 32, conversion=NamedSignalConversion(scale=1,offset=0,is_float=True,choices={}), receivers=[newNode.name], unit='rev/s^2')
trajDecelLim = can.Signal("Traj_Decel_Limit", 32, 32, conversion=NamedSignalConversion(scale=1,offset=0,is_float=True,choices={}), receivers=[newNode.name], unit='rev/s^2')
setTrajAccelMsg = can.Message(
0x012, "Set_Traj_Accel_Limits", 8, [trajAccelLim, trajDecelLim], senders=['Master']
)

# 0x013 - Set Traj Inertia
trajInertia = can.Signal("Traj_Inertia", 0, 32, is_float=True, receivers=[newNode.name], unit='Nm / (rev/s^2)')
trajInertia = can.Signal("Traj_Inertia", 0, 32, conversion=NamedSignalConversion(scale=1,offset=0,is_float=True,choices={}), receivers=[newNode.name], unit='Nm / (rev/s^2)')
trajInertiaMsg = can.Message(
0x013, "Set_Traj_Inertia", 8, [trajInertia], senders=['Master']
)

# 0x014 - Get Iq
iqSetpoint = can.Signal("Iq_Setpoint", 0, 32, is_float=True, receivers=['Master'], unit='A')
iqMeasured = can.Signal("Iq_Measured", 32, 32, is_float=True, receivers=['Master'], unit='A')
iqSetpoint = can.Signal("Iq_Setpoint", 0, 32, conversion=NamedSignalConversion(scale=1,offset=0,is_float=True,choices={}), receivers=['Master'], unit='A')
iqMeasured = can.Signal("Iq_Measured", 32, 32, conversion=NamedSignalConversion(scale=1,offset=0,is_float=True,choices={}), receivers=['Master'], unit='A')
getIqMsg = can.Message(0x014, "Get_Iq", 8, [iqSetpoint, iqMeasured], senders=[newNode.name])

# 0x015 - Get Sensorless Estimates
sensorlessPosEstimate = can.Signal("Sensorless_Pos_Estimate", 0, 32, is_float=True, receivers=['Master'], unit='rev')
sensorlessVelEstimate = can.Signal("Sensorless_Vel_Estimate", 32, 32, is_float=True, receivers=['Master'], unit='rev/s')
sensorlessPosEstimate = can.Signal("Sensorless_Pos_Estimate", 0, 32, conversion=NamedSignalConversion(scale=1,offset=0,is_float=True,choices={}), receivers=['Master'], unit='rev')
sensorlessVelEstimate = can.Signal("Sensorless_Vel_Estimate", 32, 32, conversion=NamedSignalConversion(scale=1,offset=0,is_float=True,choices={}), receivers=['Master'], unit='rev/s')
getSensorlessEstMsg = can.Message(0x015, "Get_Sensorless_Estimates", 8, [sensorlessPosEstimate, sensorlessVelEstimate], senders=[newNode.name])

# 0x016 - Reboot ODrive
rebootMsg = can.Message(0x016, "Reboot", 0, [], senders=['Master'])

# 0x017 - Get vbus Voltage and Current
busVoltage = can.Signal("Bus_Voltage", 0, 32, is_float=True, receivers=['Master'], unit='V')
busCurrent = can.Signal("Bus_Current", 32, 32, is_float=True, receivers=['Master'], unit='A')
busVoltage = can.Signal("Bus_Voltage", 0, 32, conversion=NamedSignalConversion(scale=1,offset=0,is_float=True,choices={}), receivers=['Master'], unit='V')
busCurrent = can.Signal("Bus_Current", 32, 32, conversion=NamedSignalConversion(scale=1,offset=0,is_float=True,choices={}), receivers=['Master'], unit='A')
getVbusVCMsg = can.Message(0x017, "Get_Bus_Voltage_Current", 8, [busVoltage, busCurrent], senders=[newNode.name])

# 0x018 - Clear Errors
Expand All @@ -159,20 +161,20 @@
setLinearCountMsg = can.Message(0x019, "Set_Linear_Count", 8, [position], senders=['Master'])

# 0x01A - Set Pos gain
posGain = can.Signal("Pos_Gain", 0, 32, is_float=True, receivers=[newNode.name], unit='(rev/s) / rev')
posGain = can.Signal("Pos_Gain", 0, 32, conversion=NamedSignalConversion(scale=1,offset=0,is_float=True,choices={}), receivers=[newNode.name], unit='(rev/s) / rev')
setPosGainMsg = can.Message(0x01A, "Set_Pos_Gain", 8, [posGain], senders=['Master'])

# 0x01B - Set Vel Gains
velGain = can.Signal("Vel_Gain", 0, 32, is_float=True, receivers=[newNode.name], unit='Nm / (rev/s)')
velIntGain = can.Signal("Vel_Integrator_Gain", 32, 32, is_float=True, receivers=[newNode.name], unit='(Nm / (rev/s)) / s')
velGain = can.Signal("Vel_Gain", 0, 32, conversion=NamedSignalConversion(scale=1,offset=0,is_float=True,choices={}), receivers=[newNode.name], unit='Nm / (rev/s)')
velIntGain = can.Signal("Vel_Integrator_Gain", 32, 32, conversion=NamedSignalConversion(scale=1,offset=0,is_float=True,choices={}), receivers=[newNode.name], unit='(Nm / (rev/s)) / s')
setVelGainsMsg = can.Message(0x01B, "Set_Vel_Gains", 8, [velGain, velIntGain], senders=['Master'])

# 0x01C - Get ADC Voltage
adcVoltage = can.Signal("ADC_Voltage", 0, 32, is_float=True, receivers=['Master'], unit='V')
adcVoltage = can.Signal("ADC_Voltage", 0, 32, conversion=NamedSignalConversion(scale=1,offset=0,is_float=True,choices={}), receivers=['Master'], unit='V')
getADCVoltageMsg = can.Message(0x01C, "Get_ADC_Voltage", 8, [adcVoltage], senders=[newNode.name])

# 0x01D - Controller Error
controllerError = can.Signal("Controller_Error", 0, 32, receivers=['Master'], choices={error.value: error.name for error in ControllerError})
controllerError = can.Signal("Controller_Error", 0, 32, receivers=['Master'], conversion=NamedSignalConversion(scale=1,offset=0,is_float=False,choices={error.value: error.name for error in ControllerError}))
controllerErrorMsg = can.Message(
0x01D, "Get_Controller_Error", 8, [controllerError], senders=[newNode.name]
)
Expand Down
Loading