odrive_messages/
lib.rs

1use deku::DekuError;
2
3use crate::{
4    messages::{AxisState, CanMessageWithId, ControlMode, InputMode, RebootAction},
5    sdo::ConfigValue,
6};
7
8pub mod messages;
9pub mod sdo;
10
11pub const UNADDRESSED_NODE_ID: u8 = 0x3f;
12
13pub fn parse_frame<F: embedded_can::Frame>(frame: &F) -> Result<CanMessageWithId, DekuError> {
14    CanMessageWithId::from_frame(frame)
15}
16
17pub fn estop<F: embedded_can::Frame>(node_id: u8) -> F {
18    CanMessageWithId::estop(node_id).to_frame()
19}
20
21/// Reboots the ODrive node with the specified reboot action.
22pub fn reboot<F: embedded_can::Frame>(node_id: u8, reboot_action: RebootAction) -> F {
23    CanMessageWithId::reboot(node_id, reboot_action).to_frame()
24}
25
26/// Equivalent to calling `clear_errors()`. If `identify` is true, the
27/// node will flash its LED to help identify it on the bus.
28pub fn clear_errors<F: embedded_can::Frame>(node_id: u8, identify: bool) -> F {
29    CanMessageWithId::clear_errors(node_id, identify).to_frame()
30}
31
32pub fn query_version<F: embedded_can::Frame>(node_id: u8) -> F {
33    CanMessageWithId::get_version(node_id).to_rtr_frame()
34}
35
36pub fn query_heartbeat<F: embedded_can::Frame>(node_id: u8) -> F {
37    CanMessageWithId::heartbeat(node_id).to_rtr_frame()
38}
39
40pub fn query_error<F: embedded_can::Frame>(node_id: u8) -> F {
41    CanMessageWithId::get_error(node_id).to_rtr_frame()
42}
43
44pub fn query_address<F: embedded_can::Frame>(node_id: u8) -> F {
45    CanMessageWithId::get_address(node_id).to_rtr_frame()
46}
47
48pub fn query_all_addresses<F: embedded_can::Frame>() -> F {
49    CanMessageWithId::get_all_addresses().to_rtr_frame()
50}
51
52pub fn query_encoder_estimates<F: embedded_can::Frame>(node_id: u8) -> F {
53    CanMessageWithId::get_encoder_estimates(node_id).to_rtr_frame()
54}
55
56pub fn query_iq<F: embedded_can::Frame>(node_id: u8) -> F {
57    CanMessageWithId::get_iq(node_id).to_rtr_frame()
58}
59
60pub fn query_temperature<F: embedded_can::Frame>(node_id: u8) -> F {
61    CanMessageWithId::get_temperature(node_id).to_rtr_frame()
62}
63
64pub fn query_bus_voltage_current<F: embedded_can::Frame>(node_id: u8) -> F {
65    CanMessageWithId::get_bus_voltage_current(node_id).to_rtr_frame()
66}
67
68pub fn query_torques<F: embedded_can::Frame>(node_id: u8) -> F {
69    CanMessageWithId::get_torques(node_id).to_rtr_frame()
70}
71
72pub fn query_powers<F: embedded_can::Frame>(node_id: u8) -> F {
73    CanMessageWithId::get_powers(node_id).to_rtr_frame()
74}
75
76pub fn set_address_by_serial_number<F: embedded_can::Frame>(
77    serial_number: [u8; 6],
78    new_address: u8,
79) -> F {
80    CanMessageWithId::set_address(UNADDRESSED_NODE_ID, new_address, serial_number, 0).to_frame()
81}
82
83pub fn set_axis_state<F: embedded_can::Frame>(node_id: u8, state: AxisState) -> F {
84    CanMessageWithId::set_axis_state(node_id, state).to_frame()
85}
86
87pub fn set_controller_mode<F: embedded_can::Frame>(
88    node_id: u8,
89    control_mode: ControlMode,
90    input_mode: InputMode,
91) -> F {
92    CanMessageWithId::set_controller_mode(node_id, control_mode, input_mode).to_frame()
93}
94
95/// # Units
96/// position: rev
97/// vel_feedforward: 0.001 rev/s (default, configurable)
98/// torque_feedforward: 0.001 Nm (default, configurable)
99pub fn set_input_pos<F: embedded_can::Frame>(
100    node_id: u8,
101    position: f32,
102    vel_feedforward: i16,
103    torque_feedforward: i16,
104) -> F {
105    CanMessageWithId::set_input_pos(node_id, position, vel_feedforward, torque_feedforward)
106        .to_frame()
107}
108
109/// # Units
110/// velocity: rev/s
111/// torque_feedforward: Nm
112pub fn set_input_vel<F: embedded_can::Frame>(
113    node_id: u8,
114    velocity: f32,
115    torque_feedforward: f32,
116) -> F {
117    CanMessageWithId::set_input_vel(node_id, velocity, torque_feedforward).to_frame()
118}
119
120/// # Units
121/// torque: Nm
122pub fn set_input_torque<F: embedded_can::Frame>(node_id: u8, torque: f32) -> F {
123    CanMessageWithId::set_input_torque(node_id, torque).to_frame()
124}
125
126/// # Units
127/// velocity_limit: rev/s
128/// current_limit: A
129pub fn set_limits<F: embedded_can::Frame>(
130    node_id: u8,
131    velocity_limit: f32,
132    current_limit: f32,
133) -> F {
134    CanMessageWithId::set_limits(node_id, velocity_limit, current_limit).to_frame()
135}
136
137/// # Units
138/// traj_vel_limit: rev/s
139pub fn set_traj_vel_limit<F: embedded_can::Frame>(node_id: u8, traj_vel_limit: f32) -> F {
140    CanMessageWithId::set_traj_vel_limit(node_id, traj_vel_limit).to_frame()
141}
142
143/// # Units
144/// traj_accel_limit: rev/s²
145/// traj_decel_limit: rev/s²
146pub fn set_traj_accel_limits<F: embedded_can::Frame>(
147    node_id: u8,
148    traj_accel_limit: f32,
149    traj_decel_limit: f32,
150) -> F {
151    CanMessageWithId::set_traj_accel_limits(node_id, traj_accel_limit, traj_decel_limit).to_frame()
152}
153
154/// # Units
155/// traj_inertia: Nm/(rev/s²)
156pub fn set_traj_inertia<F: embedded_can::Frame>(node_id: u8, traj_inertia: f32) -> F {
157    CanMessageWithId::set_traj_inertia(node_id, traj_inertia).to_frame()
158}
159
160/// # Units
161/// position: rev
162pub fn set_absolute_position<F: embedded_can::Frame>(node_id: u8, position: f32) -> F {
163    CanMessageWithId::set_absolute_position(node_id, position).to_frame()
164}
165
166/// # Units
167/// pos_gain: (rev/s)/rev
168pub fn set_pos_gain<F: embedded_can::Frame>(node_id: u8, pos_gain: f32) -> F {
169    CanMessageWithId::set_pos_gain(node_id, pos_gain).to_frame()
170}
171
172/// # Units
173/// vel_gain: Nm/(rev/s)
174/// vel_integrator_gain: Nm/rev
175pub fn set_vel_gains<F: embedded_can::Frame>(
176    node_id: u8,
177    vel_gain: f32,
178    vel_integrator_gain: f32,
179) -> F {
180    CanMessageWithId::set_vel_gains(node_id, vel_gain, vel_integrator_gain).to_frame()
181}
182
183pub fn read_config<F: embedded_can::Frame>(node_id: u8, endpoint_id: u16) -> F {
184    CanMessageWithId::rx_sdo(
185        node_id,
186        messages::SdoOpcode::Read,
187        endpoint_id,
188        ConfigValue::Empty,
189    )
190    .to_frame()
191}
192
193pub fn write_config<F: embedded_can::Frame>(
194    node_id: u8,
195    endpoint_id: u16,
196    value: ConfigValue,
197) -> F {
198    CanMessageWithId::rx_sdo(node_id, messages::SdoOpcode::Write, endpoint_id, value).to_frame()
199}
200
201/// Puts the ODrive into DFU mode for firmware updates. Equivalent to calling `enter_dfu_mode2()`.
202pub fn enter_dfu_mode<F: embedded_can::Frame>(node_id: u8) -> F {
203    CanMessageWithId::enter_dfu_mode(node_id).to_frame()
204}