mirror of
https://github.com/odriverobotics/ODrive.git
synced 2026-08-18 01:18:52 +08:00
+6
-3
@@ -1,11 +1,14 @@
|
||||
# Unreleased Features
|
||||
Please add a note of your changes below this heading if you make a Pull Request.
|
||||
|
||||
## [0.5.6] - Unreleased
|
||||
|
||||
### Fixed
|
||||
|
||||
* Fixed race condition in homing sequence that was causing strange behaviour
|
||||
|
||||
# Releases
|
||||
### Changed
|
||||
|
||||
* Improved can_generate_dbc.py file and resultant .dbc. Now supports 8 ODrive axes (0..7) natively
|
||||
|
||||
## [0.5.5] - 2022-08-11
|
||||
|
||||
* CANSimple messages which previously required the rtr bit to be set will now also respond if DLC = 0
|
||||
|
||||
+168
-144
@@ -1,177 +1,182 @@
|
||||
import cantools
|
||||
from cantools.database import *
|
||||
|
||||
# 0x00 - NMT Message (Reserved)
|
||||
msgList = []
|
||||
nodes = [can.Node('Master')]
|
||||
buses = [can.Bus('ODrive', None, 100000)]
|
||||
|
||||
# 0x001 - Heartbeat
|
||||
axisError = cantools.database.can.Signal("Axis_Error", 0, 32)
|
||||
axisState = cantools.database.can.Signal("Axis_State", 32, 8)
|
||||
motorFlags = cantools.database.can.Signal("Motor_Flags", 40, 8)
|
||||
encoderFlags = cantools.database.can.Signal("Encoder_Flags", 48, 8)
|
||||
controllerFlags = cantools.database.can.Signal("Controller_Flags", 56, 8)
|
||||
for axisID in range(0, 8):
|
||||
newNode = can.Node(f"ODrive_Axis{axisID}")
|
||||
nodes.append(newNode)
|
||||
|
||||
heartbeatMsg = cantools.database.can.Message(
|
||||
0x001, "Heartbeat", 8, [axisError, axisState, motorFlags, encoderFlags, controllerFlags]
|
||||
)
|
||||
# 0x00 - NMT Message (Reserved)
|
||||
|
||||
# 0x002 - E-Stop Message
|
||||
estopMsg = cantools.database.can.Message(0x002, "Estop", 0, [])
|
||||
# 0x001 - Heartbeat
|
||||
axisError = can.Signal("Axis_Error", 0, 32, receivers=['Master'])
|
||||
axisState = can.Signal("Axis_State", 32, 8, receivers=['Master'])
|
||||
motorFlags = can.Signal("Motor_Flags", 40, 8, receivers=['Master'])
|
||||
encoderFlags = can.Signal("Encoder_Flags", 48, 8, receivers=['Master'])
|
||||
controllerFlags = can.Signal("Controller_Flags", 56, 8, receivers=['Master'])
|
||||
|
||||
# 0x003 - Motor Error
|
||||
motorError = cantools.database.can.Signal("Motor_Error", 0, 32)
|
||||
motorErrorMsg = cantools.database.can.Message(0x003, "Get_Motor_Error", 8, [motorError])
|
||||
heartbeatMsg = can.Message(
|
||||
0x001, "Heartbeat", 8, [axisError, axisState, motorFlags, encoderFlags, controllerFlags], send_type='cyclic', cycle_time=100, senders=[newNode.name]
|
||||
)
|
||||
|
||||
# 0x004 - Encoder Error
|
||||
encoderError = cantools.database.can.Signal("Encoder_Error", 0, 32)
|
||||
encoderErrorMsg = cantools.database.can.Message(
|
||||
0x004, "Get_Encoder_Error", 8, [encoderError]
|
||||
)
|
||||
# 0x002 - E-Stop Message
|
||||
estopMsg = can.Message(0x002, "Estop", 0, [], senders=['Master'])
|
||||
|
||||
# 0x005 - Sensorless Error
|
||||
sensorlessError = cantools.database.can.Signal("Sensorless_Error", 0, 32)
|
||||
sensorlessErrorMsg = cantools.database.can.Message(
|
||||
0x005, "Get_Sensorless_Error", 8, [sensorlessError]
|
||||
)
|
||||
# 0x003 - Motor Error
|
||||
motorError = can.Signal("Motor_Error", 0, 32, receivers=['Master'])
|
||||
motorErrorMsg = can.Message(0x003, "Get_Motor_Error", 8, [motorError], senders=[newNode.name])
|
||||
|
||||
# 0x006 - Axis Node ID
|
||||
axisNodeID = cantools.database.can.Signal("Axis_Node_ID", 0, 32)
|
||||
axisNodeMsg = cantools.database.can.Message(0x006, "Set_Axis_Node_ID", 8, [axisNodeID])
|
||||
# 0x004 - Encoder Error
|
||||
encoderError = can.Signal("Encoder_Error", 0, 32, receivers=['Master'])
|
||||
encoderErrorMsg = can.Message(
|
||||
0x004, "Get_Encoder_Error", 8, [encoderError], senders=[newNode.name]
|
||||
)
|
||||
|
||||
# 0x007 - Requested State
|
||||
axisRequestedState = cantools.database.can.Signal("Axis_Requested_State", 0, 32)
|
||||
setAxisState = cantools.database.can.Message(
|
||||
0x007, "Set_Axis_State", 8, [axisRequestedState]
|
||||
)
|
||||
# 0x005 - Sensorless Error
|
||||
sensorlessError = can.Signal("Sensorless_Error", 0, 32, receivers=['Master'])
|
||||
sensorlessErrorMsg = can.Message(
|
||||
0x005, "Get_Sensorless_Error", 8, [sensorlessError], senders=[newNode.name]
|
||||
)
|
||||
|
||||
# 0x008 - Startup Config (Reserved)
|
||||
# 0x006 - Axis Node ID
|
||||
axisNodeID = can.Signal("Axis_Node_ID", 0, 32, receivers=[newNode.name])
|
||||
axisNodeMsg = can.Message(0x006, "Set_Axis_Node_ID", 8, [axisNodeID], senders=['Master'])
|
||||
|
||||
# 0x009 - Encoder Estimates
|
||||
encoderPosEstimate = cantools.database.can.Signal("Pos_Estimate", 0, 32, is_float=True)
|
||||
encoderVelEstimate = cantools.database.can.Signal("Vel_Estimate", 32, 32, is_float=True)
|
||||
encoderEstimates = cantools.database.can.Message(
|
||||
0x009, "Get_Encoder_Estimates", 8, [encoderPosEstimate, encoderVelEstimate]
|
||||
)
|
||||
# 0x007 - Requested State
|
||||
axisRequestedState = can.Signal("Axis_Requested_State", 0, 32, receivers=[newNode.name])
|
||||
setAxisState = can.Message(
|
||||
0x007, "Set_Axis_State", 8, [axisRequestedState], senders=['Master']
|
||||
)
|
||||
|
||||
# 0x008 - Startup Config (Reserved)
|
||||
|
||||
# 0x00A - Get Encoder Count
|
||||
encoderShadowCount = cantools.database.can.Signal("Shadow_Count", 0, 32)
|
||||
encoderCountInCPR = cantools.database.can.Signal("Count_in_CPR", 32, 32)
|
||||
encoderCountMsg = cantools.database.can.Message(
|
||||
0x00A, "Get_Encoder_Count", 8, [encoderShadowCount, encoderCountInCPR]
|
||||
)
|
||||
# 0x009 - Encoder Estimates
|
||||
encoderPosEstimate = can.Signal("Pos_Estimate", 0, 32, is_float=True, receivers=['Master'])
|
||||
encoderVelEstimate = can.Signal("Vel_Estimate", 32, 32, is_float=True, receivers=['Master'])
|
||||
encoderEstimates = can.Message(
|
||||
0x009, "Get_Encoder_Estimates", 8, [encoderPosEstimate, encoderVelEstimate], senders=[newNode.name], send_type='cyclic', cycle_time=10
|
||||
)
|
||||
|
||||
# 0x00B - Set Controller Modes
|
||||
controlMode = cantools.database.can.Signal("Control_Mode", 0, 32)
|
||||
inputMode = cantools.database.can.Signal("Input_Mode", 32, 32)
|
||||
setControllerModeMsg = cantools.database.can.Message(
|
||||
0x00B, "Set_Controller_Mode", 8, [controlMode, inputMode]
|
||||
)
|
||||
# 0x00A - Get Encoder Count
|
||||
encoderShadowCount = can.Signal("Shadow_Count", 0, 32, receivers=['Master'])
|
||||
encoderCountInCPR = can.Signal("Count_in_CPR", 32, 32, receivers=['Master'])
|
||||
encoderCountMsg = can.Message(
|
||||
0x00A, "Get_Encoder_Count", 8, [encoderShadowCount, encoderCountInCPR], senders=[newNode.name]
|
||||
)
|
||||
|
||||
# 0x00C - Set Input Pos
|
||||
inputPos = cantools.database.can.Signal("Input_Pos", 0, 32, is_float=True)
|
||||
velFF = cantools.database.can.Signal("Vel_FF", 32, 16, is_signed=True, scale=0.001)
|
||||
torqueFF = cantools.database.can.Signal(
|
||||
"Torque_FF", 48, 16, is_signed=True, scale=0.001
|
||||
)
|
||||
setInputPosMsg = cantools.database.can.Message(
|
||||
0x00C, "Set_Input_Pos", 8, [inputPos, velFF, torqueFF]
|
||||
)
|
||||
# 0x00B - Set Controller Modes
|
||||
controlMode = can.Signal("Control_Mode", 0, 32, receivers=[newNode.name])
|
||||
inputMode = can.Signal("Input_Mode", 32, 32, receivers=[newNode.name])
|
||||
setControllerModeMsg = can.Message(
|
||||
0x00B, "Set_Controller_Mode", 8, [controlMode, inputMode], senders=['Master']
|
||||
)
|
||||
|
||||
# 0x00D - Set Input Vel
|
||||
inputVel = cantools.database.can.Signal("Input_Vel", 0, 32, is_float=True)
|
||||
inputTorqueFF = cantools.database.can.Signal("Input_Torque_FF", 32, 32, is_float=True)
|
||||
setInputVelMsg = cantools.database.can.Message(
|
||||
0x00D, "Set_Input_Vel", 8, [inputVel, inputTorqueFF]
|
||||
)
|
||||
# 0x00C - Set Input Pos
|
||||
inputPos = can.Signal("Input_Pos", 0, 32, is_float=True, receivers=[newNode.name])
|
||||
velFF = can.Signal("Vel_FF", 32, 16, is_signed=True, scale=0.001, receivers=[newNode.name])
|
||||
torqueFF = can.Signal(
|
||||
"Torque_FF", 48, 16, is_signed=True, scale=0.001, receivers=[newNode.name]
|
||||
)
|
||||
setInputPosMsg = can.Message(
|
||||
0x00C, "Set_Input_Pos", 8, [inputPos, velFF, torqueFF], senders=['Master']
|
||||
)
|
||||
|
||||
# 0x00E - Set Input Torque
|
||||
inputTorque = cantools.database.can.Signal("Input_Torque", 0, 32, is_float=True)
|
||||
setInputTqMsg = cantools.database.can.Message(
|
||||
0x00E, "Set_Input_Torque", 8, [inputTorque]
|
||||
)
|
||||
# 0x00D - Set Input Vel
|
||||
inputVel = can.Signal("Input_Vel", 0, 32, is_float=True, receivers=[newNode.name])
|
||||
inputTorqueFF = can.Signal("Input_Torque_FF", 32, 32, is_float=True, receivers=[newNode.name])
|
||||
setInputVelMsg = can.Message(
|
||||
0x00D, "Set_Input_Vel", 8, [inputVel, inputTorqueFF], senders=['Master']
|
||||
)
|
||||
|
||||
# 0x00F - Set Velocity Limit
|
||||
velLimit = cantools.database.can.Signal("Velocity_Limit", 0, 32, is_float=True)
|
||||
currentLimit = cantools.database.can.Signal("Current_Limit", 32, 32, is_float=True)
|
||||
setVelLimMsg = cantools.database.can.Message(
|
||||
0x00F, "Set_Limits", 8, [velLimit, currentLimit]
|
||||
)
|
||||
# 0x00E - Set Input Torque
|
||||
inputTorque = can.Signal("Input_Torque", 0, 32, is_float=True, receivers=[newNode.name])
|
||||
setInputTqMsg = can.Message(
|
||||
0x00E, "Set_Input_Torque", 8, [inputTorque], senders=['Master']
|
||||
)
|
||||
|
||||
# 0x010 - Start Anticogging
|
||||
startAnticoggingMsg = cantools.database.can.Message(0x010, "Start_Anticogging", 0, [])
|
||||
# 0x00F - Set Velocity Limit
|
||||
velLimit = can.Signal("Velocity_Limit", 0, 32, is_float=True, receivers=[newNode.name])
|
||||
currentLimit = can.Signal("Current_Limit", 32, 32, is_float=True, receivers=[newNode.name])
|
||||
setVelLimMsg = can.Message(
|
||||
0x00F, "Set_Limits", 8, [velLimit, currentLimit], senders=['Master']
|
||||
)
|
||||
|
||||
# 0x011 - Set Traj Vel Limit
|
||||
trajVelLim = cantools.database.can.Signal("Traj_Vel_Limit", 0, 32, is_float=True)
|
||||
setTrajVelMsg = cantools.database.can.Message(
|
||||
0x011, "Set_Traj_Vel_Limit", 8, [trajVelLim]
|
||||
)
|
||||
# 0x010 - Start Anticogging
|
||||
startAnticoggingMsg = can.Message(0x010, "Start_Anticogging", 0, [], senders=['Master'])
|
||||
|
||||
# 0x012 - Set Traj Accel Limits
|
||||
trajAccelLim = cantools.database.can.Signal("Traj_Accel_Limit", 0, 32, is_float=True)
|
||||
trajDecelLim = cantools.database.can.Signal("Traj_Decel_Limit", 32, 32, is_float=True)
|
||||
setTrajAccelMsg = cantools.database.can.Message(
|
||||
0x012, "Set_Traj_Accel_Limits", 8, [trajAccelLim, trajDecelLim]
|
||||
)
|
||||
# 0x011 - Set Traj Vel Limit
|
||||
trajVelLim = can.Signal("Traj_Vel_Limit", 0, 32, is_float=True, receivers=[newNode.name])
|
||||
setTrajVelMsg = can.Message(
|
||||
0x011, "Set_Traj_Vel_Limit", 8, [trajVelLim], senders=['Master']
|
||||
)
|
||||
|
||||
# 0x013 - Set Traj Inertia
|
||||
trajInertia = cantools.database.can.Signal("Traj_Inertia", 0, 32, is_float=True)
|
||||
trajInertiaMsg = cantools.database.can.Message(
|
||||
0x013, "Set_Traj_Inertia", 8, [trajInertia]
|
||||
)
|
||||
# 0x012 - Set Traj Accel Limits
|
||||
trajAccelLim = can.Signal("Traj_Accel_Limit", 0, 32, is_float=True, receivers=[newNode.name])
|
||||
trajDecelLim = can.Signal("Traj_Decel_Limit", 32, 32, is_float=True, receivers=[newNode.name])
|
||||
setTrajAccelMsg = can.Message(
|
||||
0x012, "Set_Traj_Accel_Limits", 8, [trajAccelLim, trajDecelLim], senders=['Master']
|
||||
)
|
||||
|
||||
# 0x014 - Get Iq
|
||||
iqSetpoint = cantools.database.can.Signal("Iq_Setpoint", 0, 32, is_float=True)
|
||||
iqMeasured = cantools.database.can.Signal("Iq_Measured", 32, 32, is_float=True)
|
||||
getIqMsg = cantools.database.can.Message(0x014, "Get_Iq", 8, [iqSetpoint, iqMeasured])
|
||||
# 0x013 - Set Traj Inertia
|
||||
trajInertia = can.Signal("Traj_Inertia", 0, 32, is_float=True, receivers=[newNode.name])
|
||||
trajInertiaMsg = can.Message(
|
||||
0x013, "Set_Traj_Inertia", 8, [trajInertia], senders=['Master']
|
||||
)
|
||||
|
||||
# 0x015 - Get Sensorless Estimates
|
||||
sensorlessPosEstimate = cantools.database.can.Signal(
|
||||
"Sensorless_Pos_Estimate", 0, 32, is_float=True
|
||||
)
|
||||
sensorlessVelEstimate = cantools.database.can.Signal(
|
||||
"Sensorless_Vel_Estimate", 32, 32, is_float=True
|
||||
)
|
||||
getSensorlessEstMsg = cantools.database.can.Message(
|
||||
0x015, "Get_Sensorless_Estimates", 8, [sensorlessPosEstimate, sensorlessVelEstimate]
|
||||
)
|
||||
# 0x014 - Get Iq
|
||||
iqSetpoint = can.Signal("Iq_Setpoint", 0, 32, is_float=True, receivers=['Master'])
|
||||
iqMeasured = can.Signal("Iq_Measured", 32, 32, is_float=True, receivers=['Master'])
|
||||
getIqMsg = can.Message(0x014, "Get_Iq", 8, [iqSetpoint, iqMeasured], senders=[newNode.name])
|
||||
|
||||
# 0x016 - Reboot ODrive
|
||||
rebootMsg = cantools.database.can.Message(0x016, "Reboot", 0, [])
|
||||
# 0x015 - Get Sensorless Estimates
|
||||
sensorlessPosEstimate = can.Signal(
|
||||
"Sensorless_Pos_Estimate", 0, 32, is_float=True, receivers=['Master']
|
||||
)
|
||||
sensorlessVelEstimate = can.Signal(
|
||||
"Sensorless_Vel_Estimate", 32, 32, is_float=True, receivers=['Master']
|
||||
)
|
||||
getSensorlessEstMsg = can.Message(
|
||||
0x015, "Get_Sensorless_Estimates", 8, [sensorlessPosEstimate, sensorlessVelEstimate], senders=[newNode.name]
|
||||
)
|
||||
|
||||
# 0x017 - Get vbus Voltage and Current
|
||||
busVoltage = cantools.database.can.Signal("Bus_Voltage", 0, 32, is_float=True)
|
||||
busCurrent = cantools.database.can.Signal("Bus_Current", 32, 32, is_float=True)
|
||||
getVbusVCMsg = cantools.database.can.Message(0x017, "Get_Bus_Voltage_Current", 8, [busVoltage, busCurrent])
|
||||
# 0x016 - Reboot ODrive
|
||||
rebootMsg = can.Message(0x016, "Reboot", 0, [], senders=['Master'])
|
||||
|
||||
# 0x018 - Clear Errors
|
||||
clearErrorsMsg = cantools.database.can.Message(0x018, "Clear_Errors", 0, [])
|
||||
# 0x017 - Get vbus Voltage and Current
|
||||
busVoltage = can.Signal("Bus_Voltage", 0, 32, is_float=True, receivers=['Master'])
|
||||
busCurrent = can.Signal("Bus_Current", 32, 32, is_float=True, receivers=['Master'])
|
||||
getVbusVCMsg = can.Message(0x017, "Get_Bus_Voltage_Current", 8, [busVoltage, busCurrent], senders=[newNode.name])
|
||||
|
||||
# 0x019 - Set Linear Count
|
||||
position = cantools.database.can.Signal("Position", 0, 32, is_signed=True)
|
||||
setLinearCountMsg = cantools.database.can.Message(0x019, "Set_Linear_Count", 8, [position])
|
||||
# 0x018 - Clear Errors
|
||||
clearErrorsMsg = can.Message(0x018, "Clear_Errors", 0, [], senders=['Master'])
|
||||
|
||||
# 0x01A - Set Pos gain
|
||||
posGain = cantools.database.can.Signal("Pos_Gain", 0, 32, is_float=True)
|
||||
setPosGainMsg = cantools.database.can.Message(0x01A, "Set_Pos_Gain", 8, [posGain])
|
||||
# 0x019 - Set Linear Count
|
||||
position = can.Signal("Position", 0, 32, is_signed=True, receivers=[newNode.name])
|
||||
setLinearCountMsg = can.Message(0x019, "Set_Linear_Count", 8, [position], senders=['Master'])
|
||||
|
||||
# 0x01B - Set Vel Gains
|
||||
velGain = cantools.database.can.Signal("Vel_Gain", 0, 32, is_float=True)
|
||||
velIntGain = cantools.database.can.Signal("Vel_Integrator_Gain", 32, 32, is_float=True)
|
||||
setVelGainsMsg = cantools.database.can.Message(0x01B, "Set_Vel_gains", 8, [velGain, velIntGain])
|
||||
# 0x01A - Set Pos gain
|
||||
posGain = can.Signal("Pos_Gain", 0, 32, is_float=True, receivers=[newNode.name])
|
||||
setPosGainMsg = can.Message(0x01A, "Set_Pos_Gain", 8, [posGain], senders=['Master'])
|
||||
|
||||
# 0x01C - Get ADC Voltage
|
||||
adcVoltage = cantools.database.can.Signal("ADC_Voltage", 0, 32, is_float=True)
|
||||
getADCVoltageMsg = cantools.database.can.Message(0x01C, "Get_ADC_Voltage", 8, [adcVoltage])
|
||||
# 0x01B - Set Vel Gains
|
||||
velGain = can.Signal("Vel_Gain", 0, 32, is_float=True, receivers=[newNode.name])
|
||||
velIntGain = can.Signal("Vel_Integrator_Gain", 32, 32, is_float=True, receivers=[newNode.name])
|
||||
setVelGainsMsg = can.Message(0x01B, "Set_Vel_Gains", 8, [velGain, velIntGain], senders=['Master'])
|
||||
|
||||
# 0x01D - Controller Error
|
||||
controllerError = cantools.database.can.Signal("Controller_Error", 0, 32)
|
||||
controllerErrorMsg = cantools.database.can.Message(
|
||||
0x01D, "Get_Controller_Error", 8, [controllerError]
|
||||
)
|
||||
# 0x01C - Get ADC Voltage
|
||||
adcVoltage = can.Signal("ADC_Voltage", 0, 32, is_float=True, receivers=['Master'])
|
||||
getADCVoltageMsg = can.Message(0x01C, "Get_ADC_Voltage", 8, [adcVoltage], senders=[newNode.name])
|
||||
|
||||
db = cantools.database.can.Database(
|
||||
[
|
||||
# 0x01D - Controller Error
|
||||
controllerError = can.Signal("Controller_Error", 0, 32, receivers=['Master'])
|
||||
controllerErrorMsg = can.Message(
|
||||
0x01D, "Get_Controller_Error", 8, [controllerError], senders=[newNode.name]
|
||||
)
|
||||
|
||||
axisMsgs = [
|
||||
heartbeatMsg,
|
||||
estopMsg,
|
||||
motorErrorMsg,
|
||||
encoderErrorMsg,
|
||||
sensorlessErrorMsg,
|
||||
@@ -199,8 +204,27 @@ db = cantools.database.can.Database(
|
||||
getADCVoltageMsg,
|
||||
controllerErrorMsg,
|
||||
]
|
||||
)
|
||||
|
||||
cantools.database.dump_file(db, "odrive-cansimple.dbc")
|
||||
db = cantools.database.load_file("odrive-cansimple.dbc")
|
||||
print(db)
|
||||
masterMsgs = [
|
||||
estopMsg,
|
||||
]
|
||||
|
||||
# Prepend Axis ID to each message name
|
||||
for msg in axisMsgs:
|
||||
msg.name = f"Axis{axisID}_{msg.name}"
|
||||
msg.frame_id |= (axisID << 5)
|
||||
# for signal in msg.signals:
|
||||
# signal.name = f"{signal.name}_Axis{axisID}"
|
||||
# signal.name = f"Axis{axisID}_{signal.name}"
|
||||
|
||||
msgList.append(axisMsgs)
|
||||
|
||||
|
||||
from itertools import chain
|
||||
msgList = list(chain.from_iterable(msgList))
|
||||
|
||||
db = can.Database(msgList, nodes, buses, version='0.5.5')
|
||||
|
||||
dump_file(db, "odrive-cansimple.dbc")
|
||||
db = load_file("odrive-cansimple.dbc")
|
||||
# print(db)
|
||||
|
||||
+896
-71
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user