diff --git a/Firmware/communication/can_simple.cpp b/Firmware/communication/can_simple.cpp
index bfe35858..607495d4 100644
--- a/Firmware/communication/can_simple.cpp
+++ b/Firmware/communication/can_simple.cpp
@@ -97,6 +97,12 @@ void CANSimple::handle_can_message(CAN_message_t& msg) {
case MSG_GET_SENSORLESS_ESTIMATES:
get_sensorless_estimates_callback(axis, msg);
break;
+ case MSG_RESET_ODRIVE:
+ NVIC_SystemReset();
+ break;
+ case MSG_GET_VBUS_VOLTAGE:
+ get_vbus_voltage_callback(axis, msg);
+ break;
default:
break;
}
@@ -307,6 +313,31 @@ void CANSimple::get_iq_callback(Axis* axis, CAN_message_t& msg){
odCAN->write(txmsg);
}
+void CANSimple::get_vbus_voltage_callback(Axis* axis, CAN_message_t& msg) {
+ CAN_message_t txmsg;
+
+ txmsg.id = axis->config_.can_node_id << NUM_CMD_ID_BITS;
+ txmsg.id += MSG_GET_VBUS_VOLTAGE;
+ txmsg.isExt = false;
+ txmsg.len = 8;
+
+ uint32_t floatBytes;
+ static_assert(sizeof vbus_voltage == sizeof floatBytes);
+ std::memcpy(&floatBytes, &vbus_voltage, sizeof floatBytes);
+
+ // This also works in principle, but I don't have hardware to verify endianness
+ // std::memcpy(&txmsg.buf[0], &vbus_voltage, sizeof vbus_voltage);
+
+ txmsg.buf[0] = floatBytes;
+ txmsg.buf[1] = floatBytes >> 8;
+ txmsg.buf[2] = floatBytes >> 16;
+ txmsg.buf[3] = floatBytes >> 24;
+
+ txmsg.buf[4] = 0;
+ txmsg.buf[5] = 0;
+ txmsg.buf[6] = 0;
+ txmsg.buf[7] = 0;
+}
void CANSimple::send_heartbeat(Axis* axis) {
CAN_message_t txmsg;
diff --git a/Firmware/communication/can_simple.hpp b/Firmware/communication/can_simple.hpp
index 4ed630af..fd078c5a 100644
--- a/Firmware/communication/can_simple.hpp
+++ b/Firmware/communication/can_simple.hpp
@@ -29,6 +29,8 @@ class CANSimple {
MSG_SET_TRAJ_A_PER_CSS,
MSG_GET_IQ,
MSG_GET_SENSORLESS_ESTIMATES,
+ MSG_RESET_ODRIVE,
+ MSG_GET_VBUS_VOLTAGE,
};
static void handle_can_message(CAN_message_t& msg);
@@ -56,7 +58,8 @@ class CANSimple {
static void set_traj_accel_limits_callback(Axis* axis, CAN_message_t& msg);
static void set_traj_A_per_css_callback(Axis* axis, CAN_message_t& msg);
static void get_iq_callback(Axis* axis, CAN_message_t& msg);
- static void get_sensorless_estimates_callback(Axis* axis, CAN_message_t& ms);
+ static void get_sensorless_estimates_callback(Axis* axis, CAN_message_t& msg);
+ static void get_vbus_voltage_callback(Axis* axis, CAN_message_t& msg);
// Utility functions
diff --git a/docs/can-protocol.md b/docs/can-protocol.md
index e704439c..c66a5d7b 100644
--- a/docs/can-protocol.md
+++ b/docs/can-protocol.md
@@ -57,9 +57,12 @@ CMD ID | Name | Sender | Signals | Start byte
0x013 | Set Traj A per Count / s^2 | Master | Traj A per CSS | 0
0x014 | Get IQ\* | Axis | Iq Setpoint
Iq Measured | 0
4
0x015 | Get Sensorless Estimates\* | Master | Sensorless Pos Estimate
Sensorless Vel Estimate | 0
4
+0x016 | Reboot ODrive | Master\*\*\* | |
+0x017 | Get Vbus Voltage | Master\*\*\* | Vbus Voltage | 0
\* Note: These messages are call & response. The Master node sends a message with no payload, and the axis responds with the same ID and specified payload.
\*\* Note: These CANOpen messages are reserved to avoid bus collisions with CANOpen devices. They are not used by CAN Simple.
+\*\*\* Note: These messages can be sent to either address on a given ODrive board.
---
### Signals
@@ -91,6 +94,7 @@ Iq Setpoint | IEEE 754 Float | 32 | 1 | 0 | Intel
Iq Measured | IEEE 754 Float | 32 | 1 | 0 | Intel
Sensorless Pos Estimate | IEEE 754 Float | 32 | 1 | 0 | Intel
Sensorless Vel Estimate | IEEE 754 Float | 32 | 1 | 0 | Intel
+Vbus Voltage | IEEE 754 Float | 32 | 1 | 0 | Intel
---
## Configuring ODrive for CAN