mirror of
https://github.com/odriverobotics/ODrive.git
synced 2026-08-17 17:01:58 +08:00
Merge pull request #730 from odriverobotics/devel
Fw v0.5.6 Release Candidate
This commit is contained in:
@@ -65,3 +65,4 @@ GUI/node_modules
|
||||
GUI/build
|
||||
|
||||
docs/reStructuredText/_build/
|
||||
tools/odrive-cansimple.ini
|
||||
|
||||
+38
-3
@@ -1,7 +1,42 @@
|
||||
# Unreleased Features
|
||||
Please add a note of your changes below this heading if you make a Pull Request.
|
||||
|
||||
# Releases
|
||||
## [0.5.6] - Unreleased
|
||||
|
||||
### Fixed
|
||||
|
||||
* Fixed race condition in homing sequence that was causing strange behaviour. Fixes [#634](https://github.com/odriverobotics/ODrive/issues/634)]
|
||||
* When using a load encoder, CAN will report the correct position and velocity.
|
||||
* When using a load encoder, homing will reset the correct linear position. Fixes [#651](https://github.com/odriverobotics/ODrive/issues/651)
|
||||
* Implemented CAN controller error message, which was previously defined but not actually implemented.
|
||||
* Get Vbus Voltage message updated to match ODrive Pro's CANSimple implementation.
|
||||
* `vel_setpoint` and `torque_setpoint` will be clamped to `vel_limit` and the active torque limit. Fixes [#647](https://github.com/odriverobotics/ODrive/issues/647)
|
||||
|
||||
### Added
|
||||
|
||||
* Added public `controller.get_anticogging_value(uint32)` fibre function to index into the the cogging map. Fixes [#690](https://github.com/odriverobotics/ODrive/issues/690)
|
||||
* Added Get ADC Voltage message to CAN (0x1C). Send the desired GPIO number in byte 1, and the ODrive will respond with the ADC voltage from that pin (if previously configured for analog)
|
||||
* Added CAN heartbeat message flags for motor, controller, and encoder error. If flag is true, fetch the corresponding error with the respective message.
|
||||
* Added scoped enums, e.g. `CONTROL_MODE_POSITION_CONTROL` can be used as `ControlMode.POSITION_CONTROL`
|
||||
* Added more cyclic messages to can. Use the `rate_ms` values in `<odrv>.<axis>.config.can` to set the cycle rate of the message in milliseconds. Set a rate to 0 to disable sending. The following variables are avaialble:
|
||||
|
||||
Command ID | Rate Variable | Message Name
|
||||
:-- | :-- | :--
|
||||
0x01 | `heartbeat_rate_ms` | Heartbeat
|
||||
0x09 | `encoder_rate_ms` | Get Encoder Estimates
|
||||
0x03 | `motor_error_rate_ms` | Get Motor Error
|
||||
0x04 | `encoder_error_rate_ms` | Get Encoder Error
|
||||
0x1D | `controller_error_rate_ms` | Get Controller Error
|
||||
0x05 | `sensorless_error_rate_ms` | Get Sensorless Error
|
||||
0x0A | `encoder_count_rate_ms` | Get Encoder Count
|
||||
0x14 | `iq_rate_ms` | Get Iq
|
||||
0x15 | `sensorless_rate_ms` | Get Sensorless Estimates
|
||||
0x17 | `bus_vi_rate_ms` | Get Bus Voltage Current
|
||||
|
||||
### Changed
|
||||
|
||||
* Improved can_generate_dbc.py file and resultant .dbc. Now supports 8 ODrive axes (0..7) natively
|
||||
* Add units and value tables to every signal in odrive-cansimple.dbc
|
||||
* Autogenerate odrive-cansimple.dbc on compile
|
||||
|
||||
## [0.5.5] - 2022-08-11
|
||||
|
||||
* CANSimple messages which previously required the rtr bit to be set will now also respond if DLC = 0
|
||||
|
||||
@@ -33,6 +33,7 @@ all:
|
||||
@tup --quiet -no-environ-check
|
||||
@$(PY_CMD) interface_generator_stub.py --definitions odrive-interface.yaml --template ../tools/enums_template.j2 --output ../tools/odrive/enums.py
|
||||
@$(PY_CMD) interface_generator_stub.py --definitions odrive-interface.yaml --template ../tools/arduino_enums_template.j2 --output ../Arduino/ODriveArduino/ODriveEnums.h
|
||||
@cd ../tools/ && $(PY_CMD) create_can_dbc.py
|
||||
|
||||
# Copy libfibre files to odrivetool if they were built
|
||||
@ ! test -f "fibre-cpp/build/libfibre-linux-amd64.so" || cp fibre-cpp/build/libfibre-linux-amd64.so ../tools/odrive/pyfibre/fibre/
|
||||
|
||||
@@ -354,9 +354,6 @@ bool Axis::run_closed_loop_control_loop() {
|
||||
// Slowly drive in the negative direction at homing_speed until the min endstop is pressed
|
||||
// When pressed, set the linear count to the offset (default 0), and then go to position 0
|
||||
bool Axis::run_homing() {
|
||||
Controller::ControlMode stored_control_mode = controller_.config_.control_mode;
|
||||
Controller::InputMode stored_input_mode = controller_.config_.input_mode;
|
||||
|
||||
// TODO: theoretically this check should be inside the update loop,
|
||||
// otherwise someone could disable the endstop while homing is in progress.
|
||||
if (!min_endstop_.config_.enabled) {
|
||||
@@ -424,13 +421,20 @@ bool Axis::run_homing() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set the current position to 0.
|
||||
encoder_.set_linear_count(0);
|
||||
controller_.input_pos_ = 0;
|
||||
// Set the current position to 0, the target to zero, and make sure we're path planning from 0 to 0
|
||||
encoder_.set_linear_count(0);
|
||||
const auto load_encoder_axis = controller_.config_.load_encoder_axis;
|
||||
if(load_encoder_axis != axis_num_ && load_encoder_axis < AXIS_COUNT) {
|
||||
axes[load_encoder_axis].encoder_.set_linear_count(0);
|
||||
}
|
||||
controller_.input_pos_ = 0.0f;
|
||||
controller_.pos_setpoint_ = 0.0f;
|
||||
controller_.vel_setpoint_ = 0.0f;
|
||||
controller_.input_pos_updated();
|
||||
|
||||
controller_.config_.control_mode = stored_control_mode;
|
||||
controller_.config_.input_mode = stored_input_mode;
|
||||
// Force encoder estimate to update
|
||||
osDelay(1);
|
||||
|
||||
homing_.is_homed = true;
|
||||
|
||||
return check_for_errors();
|
||||
@@ -540,9 +544,13 @@ void Axis::run_state_machine_loop() {
|
||||
} break;
|
||||
|
||||
case AXIS_STATE_HOMING: {
|
||||
//if (odrv.any_error())
|
||||
// goto invalid_state_label;
|
||||
Controller::ControlMode stored_control_mode = controller_.config_.control_mode;
|
||||
Controller::InputMode stored_input_mode = controller_.config_.input_mode;
|
||||
|
||||
status = run_homing();
|
||||
|
||||
controller_.config_.control_mode = stored_control_mode;
|
||||
controller_.config_.input_mode = stored_input_mode;
|
||||
} break;
|
||||
|
||||
case AXIS_STATE_ENCODER_OFFSET_CALIBRATION: {
|
||||
|
||||
@@ -56,6 +56,14 @@ public:
|
||||
bool is_extended = false;
|
||||
uint32_t heartbeat_rate_ms = 100;
|
||||
uint32_t encoder_rate_ms = 10;
|
||||
uint32_t motor_error_rate_ms = 0;
|
||||
uint32_t encoder_error_rate_ms = 0;
|
||||
uint32_t controller_error_rate_ms = 0;
|
||||
uint32_t sensorless_error_rate_ms = 0;
|
||||
uint32_t encoder_count_rate_ms = 0;
|
||||
uint32_t iq_rate_ms = 0;
|
||||
uint32_t sensorless_rate_ms = 0;
|
||||
uint32_t bus_vi_rate_ms = 0;
|
||||
};
|
||||
|
||||
struct Config_t {
|
||||
@@ -101,6 +109,14 @@ public:
|
||||
struct CAN_t {
|
||||
uint32_t last_heartbeat = 0;
|
||||
uint32_t last_encoder = 0;
|
||||
uint32_t last_motor_error = 0;
|
||||
uint32_t last_encoder_error = 0;
|
||||
uint32_t last_controller_error = 0;
|
||||
uint32_t last_sensorless_error = 0;
|
||||
uint32_t last_encoder_count = 0;
|
||||
uint32_t last_iq = 0;
|
||||
uint32_t last_sensorless = 0;
|
||||
uint32_t last_bus_vi = 0;
|
||||
};
|
||||
|
||||
Axis(int axis_num,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
|
||||
#include "odrive_main.h"
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
|
||||
bool Controller::apply_config() {
|
||||
config_.parent = this;
|
||||
@@ -53,6 +54,20 @@ void Controller::start_anticogging_calibration() {
|
||||
}
|
||||
}
|
||||
|
||||
float Controller::remove_anticogging_bias()
|
||||
{
|
||||
auto& cogmap = config_.anticogging.cogging_map;
|
||||
|
||||
auto sum = std::accumulate(std::begin(cogmap), std::end(cogmap), 0.0f);
|
||||
auto average = sum / std::size(cogmap);
|
||||
|
||||
for(auto& val : cogmap) {
|
||||
val -= average;
|
||||
}
|
||||
|
||||
return average;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This anti-cogging implementation iterates through each encoder position,
|
||||
@@ -267,6 +282,13 @@ bool Controller::update() {
|
||||
|
||||
}
|
||||
|
||||
// Never command a setpoint beyond its limit
|
||||
if(config_.enable_vel_limit) {
|
||||
vel_setpoint_ = std::clamp(vel_setpoint_, -config_.vel_limit, config_.vel_limit);
|
||||
}
|
||||
const float Tlim = axis_->motor_.max_available_torque();
|
||||
torque_setpoint_ = std::clamp(torque_setpoint_, -Tlim, Tlim);
|
||||
|
||||
// Position control
|
||||
// TODO Decide if we want to use encoder or pll position here
|
||||
float gain_scheduling_multiplier = 1.0f;
|
||||
@@ -373,7 +395,6 @@ bool Controller::update() {
|
||||
|
||||
// Torque limiting
|
||||
bool limited = false;
|
||||
float Tlim = axis_->motor_.max_available_torque();
|
||||
if (torque > Tlim) {
|
||||
limited = true;
|
||||
torque = Tlim;
|
||||
|
||||
@@ -81,7 +81,12 @@ public:
|
||||
|
||||
// TODO: make this more similar to other calibration loops
|
||||
void start_anticogging_calibration();
|
||||
float remove_anticogging_bias();
|
||||
bool anticogging_calibration(float pos_estimate, float vel_estimate);
|
||||
|
||||
float get_anticogging_value(uint32_t index) {
|
||||
return (index < 3600) ? config_.anticogging.cogging_map[index] : 0.0f;
|
||||
}
|
||||
|
||||
void update_filter_gains();
|
||||
bool update();
|
||||
|
||||
@@ -18,7 +18,6 @@ class Endstop {
|
||||
void set_debounce_ms(uint32_t value) { debounce_ms = value; parent->apply_config(); }
|
||||
};
|
||||
|
||||
Endstop() {}
|
||||
|
||||
Endstop::Config_t config_;
|
||||
Axis* axis_ = nullptr;
|
||||
|
||||
+14
-7
@@ -328,9 +328,16 @@ boards = {
|
||||
|
||||
-- Toolchain setup -------------------------------------------------------------
|
||||
|
||||
CC='arm-none-eabi-gcc -std=c99'
|
||||
CXX='arm-none-eabi-g++ -std=c++17 -Wno-register'
|
||||
LINKER='arm-none-eabi-g++'
|
||||
CCPATH = tup.getconfig('ARM_COMPILER_PATH')
|
||||
if CCPATH == "" then
|
||||
CCPATH=''
|
||||
else
|
||||
CCPATH = CCPATH..'/'
|
||||
end
|
||||
|
||||
CC=CCPATH..'arm-none-eabi-gcc -std=c99'
|
||||
CXX=CCPATH..'arm-none-eabi-g++ -std=c++17 -Wno-register'
|
||||
LINKER=CCPATH..'arm-none-eabi-g++'
|
||||
|
||||
-- C-specific flags
|
||||
CFLAGS += '-D__weak="__attribute__((weak))"'
|
||||
@@ -440,13 +447,13 @@ tup.frule{
|
||||
outputs={'build/ODriveFirmware.elf', extra_outputs={'build/ODriveFirmware.map'}}
|
||||
}
|
||||
-- display the size
|
||||
tup.frule{inputs={'build/ODriveFirmware.elf'}, command='arm-none-eabi-size %f'}
|
||||
tup.frule{inputs={'build/ODriveFirmware.elf'}, command=CCPATH..'arm-none-eabi-size %f'}
|
||||
-- create *.hex and *.bin output formats
|
||||
tup.frule{inputs={'build/ODriveFirmware.elf'}, command='arm-none-eabi-objcopy -O ihex %f %o', outputs={'build/ODriveFirmware.hex'}}
|
||||
tup.frule{inputs={'build/ODriveFirmware.elf'}, command='arm-none-eabi-objcopy -O binary -S %f %o', outputs={'build/ODriveFirmware.bin'}}
|
||||
tup.frule{inputs={'build/ODriveFirmware.elf'}, command=CCPATH..'arm-none-eabi-objcopy -O ihex %f %o', outputs={'build/ODriveFirmware.hex'}}
|
||||
tup.frule{inputs={'build/ODriveFirmware.elf'}, command=CCPATH..'arm-none-eabi-objcopy -O binary -S %f %o', outputs={'build/ODriveFirmware.bin'}}
|
||||
|
||||
if tup.getconfig('ENABLE_DISASM') == 'true' then
|
||||
tup.frule{inputs={'build/ODriveFirmware.elf'}, command='arm-none-eabi-objdump %f -dSC > %o', outputs={'build/ODriveFirmware.asm'}}
|
||||
tup.frule{inputs={'build/ODriveFirmware.elf'}, command=CCPATH..'arm-none-eabi-objdump %f -dSC > %o', outputs={'build/ODriveFirmware.asm'}}
|
||||
end
|
||||
|
||||
if tup.getconfig('DOCTEST') == 'true' then
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "can_simple.hpp"
|
||||
|
||||
#include <odrive_main.h>
|
||||
#include <functional>
|
||||
|
||||
bool CANSimple::init() {
|
||||
for (size_t i = 0; i < AXIS_COUNT; ++i) {
|
||||
@@ -135,9 +136,9 @@ void CANSimple::do_command(Axis& axis, const can_Message_t& msg) {
|
||||
case MSG_RESET_ODRIVE:
|
||||
NVIC_SystemReset();
|
||||
break;
|
||||
case MSG_GET_VBUS_VOLTAGE:
|
||||
case MSG_GET_BUS_VOLTAGE_CURRENT:
|
||||
if (msg.rtr || msg.len == 0)
|
||||
get_vbus_voltage_callback(axis);
|
||||
get_bus_voltage_current_callback(axis);
|
||||
break;
|
||||
case MSG_CLEAR_ERRORS:
|
||||
clear_errors_callback(axis, msg);
|
||||
@@ -151,6 +152,12 @@ void CANSimple::do_command(Axis& axis, const can_Message_t& msg) {
|
||||
case MSG_SET_VEL_GAINS:
|
||||
set_vel_gains_callback(axis, msg);
|
||||
break;
|
||||
case MSG_GET_ADC_VOLTAGE:
|
||||
get_adc_voltage_callback(axis, msg);
|
||||
break;
|
||||
case MSG_GET_CONTROLLER_ERROR:
|
||||
get_controller_error_callback(axis);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -200,6 +207,18 @@ bool CANSimple::get_sensorless_error_callback(const Axis& axis) {
|
||||
return canbus_->send_message(txmsg);
|
||||
}
|
||||
|
||||
bool CANSimple::get_controller_error_callback(const Axis& axis) {
|
||||
can_Message_t txmsg;
|
||||
txmsg.id = axis.config_.can.node_id << NUM_CMD_ID_BITS;
|
||||
txmsg.id += MSG_GET_CONTROLLER_ERROR; // heartbeat ID
|
||||
txmsg.isExt = axis.config_.can.is_extended;
|
||||
txmsg.len = 8;
|
||||
|
||||
can_setSignal(txmsg, axis.controller_.error_, 0, 32, true);
|
||||
|
||||
return canbus_->send_message(txmsg);
|
||||
}
|
||||
|
||||
void CANSimple::set_axis_nodeid_callback(Axis& axis, const can_Message_t& msg) {
|
||||
axis.config_.can.node_id = can_getSignal<uint32_t>(msg, 0, 32, true);
|
||||
}
|
||||
@@ -219,8 +238,8 @@ bool CANSimple::get_encoder_estimates_callback(const Axis& axis) {
|
||||
txmsg.isExt = axis.config_.can.is_extended;
|
||||
txmsg.len = 8;
|
||||
|
||||
can_setSignal<float>(txmsg, axis.encoder_.pos_estimate_.any().value_or(0.0f), 0, 32, true);
|
||||
can_setSignal<float>(txmsg, axis.encoder_.vel_estimate_.any().value_or(0.0f), 32, 32, true);
|
||||
can_setSignal<float>(txmsg, axis.controller_.pos_estimate_linear_src_.any().value_or(0.0f), 0, 32, true);
|
||||
can_setSignal<float>(txmsg, axis.controller_.vel_estimate_src_.any().value_or(0.0f), 32, 32, true);
|
||||
|
||||
return canbus_->send_message(txmsg);
|
||||
}
|
||||
@@ -330,21 +349,40 @@ bool CANSimple::get_iq_callback(const Axis& axis) {
|
||||
return canbus_->send_message(txmsg);
|
||||
}
|
||||
|
||||
bool CANSimple::get_vbus_voltage_callback(const Axis& axis) {
|
||||
bool CANSimple::get_bus_voltage_current_callback(const Axis& axis) {
|
||||
can_Message_t txmsg;
|
||||
|
||||
txmsg.id = axis.config_.can.node_id << NUM_CMD_ID_BITS;
|
||||
txmsg.id += MSG_GET_VBUS_VOLTAGE;
|
||||
txmsg.id += MSG_GET_BUS_VOLTAGE_CURRENT;
|
||||
txmsg.isExt = axis.config_.can.is_extended;
|
||||
txmsg.len = 8;
|
||||
|
||||
uint32_t floatBytes;
|
||||
static_assert(sizeof(vbus_voltage) == sizeof(floatBytes));
|
||||
static_assert(sizeof(float) == sizeof(vbus_voltage));
|
||||
static_assert(sizeof(float) == sizeof(ibus_));
|
||||
can_setSignal<float>(txmsg, vbus_voltage, 0, 32, true);
|
||||
can_setSignal<float>(txmsg, ibus_, 32, 32, true);
|
||||
|
||||
return canbus_->send_message(txmsg);
|
||||
}
|
||||
|
||||
bool CANSimple::get_adc_voltage_callback(const Axis& axis, const can_Message_t& msg) {
|
||||
can_Message_t txmsg;
|
||||
|
||||
txmsg.id = axis.config_.can.node_id << NUM_CMD_ID_BITS;
|
||||
txmsg.id += MSG_GET_ADC_VOLTAGE;
|
||||
txmsg.isExt = axis.config_.can.is_extended;
|
||||
txmsg.len = 8;
|
||||
|
||||
auto gpio_num = can_getSignal<uint8_t>(msg, 0, 8, true);
|
||||
if (gpio_num < GPIO_COUNT) {
|
||||
auto voltage = get_adc_voltage(get_gpio(gpio_num));
|
||||
can_setSignal<float>(txmsg, voltage, 0, 32, true);
|
||||
return canbus_->send_message(txmsg);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void CANSimple::clear_errors_callback(Axis& axis, const can_Message_t& msg) {
|
||||
odrv.clear_errors(); // TODO: might want to clear axis errors only
|
||||
}
|
||||
@@ -361,26 +399,38 @@ uint32_t CANSimple::service_stack() {
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& a : axes) {
|
||||
MEASURE_TIME(a.task_times_.can_heartbeat) {
|
||||
if (a.config_.can.heartbeat_rate_ms > 0) {
|
||||
if ((now - a.can_.last_heartbeat) >= a.config_.can.heartbeat_rate_ms) {
|
||||
if (send_heartbeat(a))
|
||||
a.can_.last_heartbeat = now;
|
||||
struct periodic {
|
||||
const uint32_t& rate;
|
||||
uint32_t& last_time;
|
||||
bool (CANSimple::* callback)(const Axis& axis);
|
||||
};
|
||||
|
||||
for (auto& axis : axes) {
|
||||
std::array<periodic, 10> periodics = {{
|
||||
{axis.config_.can.heartbeat_rate_ms, axis.can_.last_heartbeat, &CANSimple::send_heartbeat},
|
||||
{axis.config_.can.encoder_rate_ms, axis.can_.last_encoder, &CANSimple::get_encoder_estimates_callback},
|
||||
{axis.config_.can.motor_error_rate_ms, axis.can_.last_motor_error, &CANSimple::get_motor_error_callback},
|
||||
{axis.config_.can.encoder_error_rate_ms, axis.can_.last_encoder_error, &CANSimple::get_encoder_error_callback},
|
||||
{axis.config_.can.controller_error_rate_ms, axis.can_.last_controller_error, &CANSimple::get_controller_error_callback},
|
||||
{axis.config_.can.sensorless_error_rate_ms, axis.can_.last_sensorless_error, &CANSimple::get_sensorless_error_callback},
|
||||
{axis.config_.can.encoder_count_rate_ms, axis.can_.last_encoder_count, &CANSimple::get_encoder_count_callback},
|
||||
{axis.config_.can.iq_rate_ms, axis.can_.last_iq, &CANSimple::get_iq_callback},
|
||||
{axis.config_.can.sensorless_rate_ms, axis.can_.last_sensorless, &CANSimple::get_sensorless_estimates_callback},
|
||||
{axis.config_.can.bus_vi_rate_ms, axis.can_.last_bus_vi, &CANSimple::get_bus_voltage_current_callback},
|
||||
}};
|
||||
|
||||
MEASURE_TIME(axis.task_times_.can_heartbeat) {
|
||||
for (auto& msg : periodics) {
|
||||
if (msg.rate > 0) {
|
||||
if ((now - msg.last_time) >= msg.rate) {
|
||||
if (std::invoke(msg.callback, this, axis)) {
|
||||
msg.last_time = now;
|
||||
}
|
||||
}
|
||||
|
||||
int nextAxisService = msg.last_time + msg.rate - now;
|
||||
nextServiceTime = std::min(nextServiceTime, static_cast<uint32_t>(std::max(0, nextAxisService)));
|
||||
}
|
||||
|
||||
int nextAxisService = a.can_.last_heartbeat + a.config_.can.heartbeat_rate_ms - now;
|
||||
nextServiceTime = std::min(nextServiceTime, static_cast<uint32_t>(std::max(0, nextAxisService)));
|
||||
}
|
||||
|
||||
if (a.config_.can.encoder_rate_ms > 0) {
|
||||
if ((now - a.can_.last_encoder) >= a.config_.can.encoder_rate_ms) {
|
||||
if (get_encoder_estimates_callback(a))
|
||||
a.can_.last_encoder = now;
|
||||
}
|
||||
|
||||
int nextAxisService = a.can_.last_encoder + a.config_.can.encoder_rate_ms - now;
|
||||
nextServiceTime = std::min(nextServiceTime, static_cast<uint32_t>(std::max(0, nextAxisService)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -399,20 +449,19 @@ bool CANSimple::send_heartbeat(const Axis& axis) {
|
||||
can_setSignal(txmsg, uint8_t(axis.current_state_), 32, 8, true);
|
||||
|
||||
// Motor flags
|
||||
uint8_t motorFlags = 0; // reserved
|
||||
uint8_t motorFlags = axis.motor_.error_ != 0;
|
||||
|
||||
// Encoder flags
|
||||
uint8_t encoderFlags = 0; // reserved
|
||||
uint8_t encoderFlags = axis.encoder_.error_ != 0;
|
||||
|
||||
// Controller flags
|
||||
uint8_t controllerFlags = 0;
|
||||
uint8_t controllerFlags =axis.controller_.error_ != 0;
|
||||
uint8_t trajDone = uint8_t(axis.controller_.trajectory_done_) << 7;
|
||||
controllerFlags |= trajDone;
|
||||
|
||||
can_setSignal(txmsg, motorFlags, 40, 8, true);
|
||||
can_setSignal(txmsg, encoderFlags, 48, 8, true);
|
||||
can_setSignal(txmsg, controllerFlags, 56, 8, true);
|
||||
// can_setSignal(txmsg, axis.current_state_, 32, 32, true);
|
||||
|
||||
return canbus_->send_message(txmsg);
|
||||
}
|
||||
|
||||
@@ -30,11 +30,13 @@ class CANSimple {
|
||||
MSG_GET_IQ,
|
||||
MSG_GET_SENSORLESS_ESTIMATES,
|
||||
MSG_RESET_ODRIVE,
|
||||
MSG_GET_VBUS_VOLTAGE,
|
||||
MSG_GET_BUS_VOLTAGE_CURRENT,
|
||||
MSG_CLEAR_ERRORS,
|
||||
MSG_SET_LINEAR_COUNT,
|
||||
MSG_SET_POS_GAIN,
|
||||
MSG_SET_VEL_GAINS,
|
||||
MSG_GET_ADC_VOLTAGE,
|
||||
MSG_GET_CONTROLLER_ERROR,
|
||||
MSG_CO_HEARTBEAT_CMD = 0x700, // CANOpen NMT Heartbeat SEND
|
||||
};
|
||||
|
||||
@@ -61,7 +63,9 @@ class CANSimple {
|
||||
bool get_encoder_count_callback(const Axis& axis);
|
||||
bool get_iq_callback(const Axis& axis);
|
||||
bool get_sensorless_estimates_callback(const Axis& axis);
|
||||
bool get_vbus_voltage_callback(const Axis& axis);
|
||||
bool get_bus_voltage_current_callback(const Axis& axis);
|
||||
// msg.rtr bit must NOT be set
|
||||
bool get_adc_voltage_callback(const Axis& axis, const can_Message_t& msg);
|
||||
|
||||
// Set functions
|
||||
static void set_axis_nodeid_callback(Axis& axis, const can_Message_t& msg);
|
||||
@@ -106,4 +110,4 @@ class CANSimple {
|
||||
bool extended_node_ids_[AXIS_COUNT];
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -600,6 +600,14 @@ interfaces:
|
||||
is_extended: bool
|
||||
heartbeat_rate_ms: uint32
|
||||
encoder_rate_ms: uint32
|
||||
motor_error_rate_ms: uint32
|
||||
encoder_error_rate_ms: uint32
|
||||
controller_error_rate_ms: uint32
|
||||
sensorless_error_rate_ms: uint32
|
||||
encoder_count_rate_ms: uint32
|
||||
iq_rate_ms: uint32
|
||||
sensorless_rate_ms: uint32
|
||||
bus_vi_rate_ms: uint32
|
||||
|
||||
ODrive.ThermistorCurrentLimiter:
|
||||
c_is_class: False
|
||||
@@ -1188,6 +1196,8 @@ interfaces:
|
||||
usually corresponds roughly to the current position of the axis.'
|
||||
}
|
||||
start_anticogging_calibration:
|
||||
remove_anticogging_bias: {out: {val: float32}}
|
||||
get_anticogging_value: {in: {index: uint32}, out: {val: float32}}
|
||||
|
||||
|
||||
ODrive.Encoder:
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
# Copy this file to tup.config and adapt it to your needs
|
||||
# make sure this fits your board
|
||||
#CONFIG_BOARD_VERSION=v3.5-24V
|
||||
#CONFIG_BOARD_VERSION=v3.6-56V
|
||||
CONFIG_DEBUG=false
|
||||
CONFIG_DOCTEST=false
|
||||
CONFIG_USE_LTO=false
|
||||
|
||||
# Path to the ARM compiler /bin folder (optional)
|
||||
#CONFIG_ARM_COMPILER_PATH=C:/Tools/ARM/9-2019-q4-major/bin
|
||||
|
||||
# Uncomment this to error on compilation warnings
|
||||
#CONFIG_STRICT=true
|
||||
|
||||
Generated
+8
-106
@@ -3193,24 +3193,6 @@
|
||||
"integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/app-builder-lib/node_modules/debug": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz",
|
||||
"integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==",
|
||||
"deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ms": "2.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/app-builder-lib/node_modules/ejs": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.3.tgz",
|
||||
@@ -4289,24 +4271,6 @@
|
||||
"node": ">=8.2.5"
|
||||
}
|
||||
},
|
||||
"node_modules/builder-util-runtime/node_modules/debug": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz",
|
||||
"integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==",
|
||||
"deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ms": "2.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/builder-util/node_modules/ansi-styles": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
|
||||
@@ -4363,24 +4327,6 @@
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/builder-util/node_modules/debug": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz",
|
||||
"integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==",
|
||||
"deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ms": "2.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/builder-util/node_modules/fs-extra": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz",
|
||||
@@ -10598,15 +10544,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/jszip": {
|
||||
"version": "3.5.0",
|
||||
"resolved": "https://registry.npmjs.org/jszip/-/jszip-3.5.0.tgz",
|
||||
"integrity": "sha512-WRtu7TPCmYePR1nazfrtuF216cIVon/3GWOvHS9QR5bIwSbnxtdpma6un3jyGGNhHsKCSzn5Ypk+EkDRvTGiFA==",
|
||||
"version": "3.10.1",
|
||||
"resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz",
|
||||
"integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"lie": "~3.3.0",
|
||||
"pako": "~1.0.2",
|
||||
"readable-stream": "~2.3.6",
|
||||
"set-immediate-shim": "~1.0.1"
|
||||
"setimmediate": "^1.0.5"
|
||||
}
|
||||
},
|
||||
"node_modules/kew": {
|
||||
@@ -14512,15 +14458,6 @@
|
||||
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/set-immediate-shim": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz",
|
||||
"integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/set-value": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
|
||||
@@ -21368,15 +21305,6 @@
|
||||
"integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==",
|
||||
"dev": true
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz",
|
||||
"integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
},
|
||||
"ejs": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.3.tgz",
|
||||
@@ -22293,15 +22221,6 @@
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz",
|
||||
"integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
},
|
||||
"fs-extra": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz",
|
||||
@@ -22364,17 +22283,6 @@
|
||||
"requires": {
|
||||
"debug": "^4.2.0",
|
||||
"sax": "^1.2.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz",
|
||||
"integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"builtin-status-codes": {
|
||||
@@ -27317,15 +27225,15 @@
|
||||
}
|
||||
},
|
||||
"jszip": {
|
||||
"version": "3.5.0",
|
||||
"resolved": "https://registry.npmjs.org/jszip/-/jszip-3.5.0.tgz",
|
||||
"integrity": "sha512-WRtu7TPCmYePR1nazfrtuF216cIVon/3GWOvHS9QR5bIwSbnxtdpma6un3jyGGNhHsKCSzn5Ypk+EkDRvTGiFA==",
|
||||
"version": "3.10.1",
|
||||
"resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz",
|
||||
"integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lie": "~3.3.0",
|
||||
"pako": "~1.0.2",
|
||||
"readable-stream": "~2.3.6",
|
||||
"set-immediate-shim": "~1.0.1"
|
||||
"setimmediate": "^1.0.5"
|
||||
}
|
||||
},
|
||||
"kew": {
|
||||
@@ -30601,12 +30509,6 @@
|
||||
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
|
||||
"dev": true
|
||||
},
|
||||
"set-immediate-shim": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz",
|
||||
"integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=",
|
||||
"dev": true
|
||||
},
|
||||
"set-value": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
|
||||
|
||||
@@ -10,3 +10,5 @@ To read the voltage on GPIO1 in odrivetool the following would be entered: :code
|
||||
Similar to RC PWM input, analog inputs can also be used to feed any of the numerical properties that are visible in :code:`odrivetool`.
|
||||
This is done by configuring :code:`odrv0.config.gpio3_analog_mapping` and :code:`odrv0.config.gpio4_analog_mapping`.
|
||||
Refer to :ref:`RC PWM <rc-pwm-doc>` for instructions on how to configure the mappings.
|
||||
|
||||
You may also retrieve voltage measurements from analog inputs via the CAN protocol by sending the Get ADC Voltage message with the GPIO number of the analog input you wish to read. Refer to :ref: `CAN Protocol <can-protocol-doc>` for guidance on how to use the CAN Protocol.
|
||||
+56
-6
@@ -74,6 +74,7 @@ All multibyte values are little endian (aka Intel format, aka least significant
|
||||
* These messages are call & response. The Master node sends a message with the RTR bit set, and the axis responds with the same ID and specified payload.
|
||||
* These CANOpen messages are reserved to avoid bus collisions with CANOpen devices. They are not used by CAN Simple.
|
||||
* These messages can be sent to either address on a given ODrive board.
|
||||
* You must send a valid GPIO pin number in the first byte to recieve coreect ADC voltage feedback. Since you're both sending and receiving data the RTR bit must be set to false.
|
||||
|
||||
|
||||
Cyclic Messages
|
||||
@@ -82,24 +83,73 @@ Cyclic Messages
|
||||
Cyclic messages are sent by ODrive on a timer without a request. As of firmware verion `0.5.4`, the Cyclic messsages are:
|
||||
|
||||
.. list-table::
|
||||
:widths: 25 25 50
|
||||
:widths: 25 25 25 50
|
||||
:header-rows: 1
|
||||
|
||||
* - ID
|
||||
- Name
|
||||
- Rate (ms)
|
||||
* - 0x001
|
||||
- ODrive Heartbeat Message
|
||||
- Config Variable
|
||||
- Default Rate (ms)
|
||||
* - 0x01
|
||||
- Heartbeat
|
||||
- `heartbeat_rate_ms`
|
||||
- 100
|
||||
* - 0x009
|
||||
- Encoder Estimates
|
||||
* - 0x09
|
||||
- Get Encoder Estimates
|
||||
- `encoder_rate_ms`
|
||||
- 10
|
||||
* - 0x03
|
||||
- Get Motor Error
|
||||
- `motor_error_rate_ms`
|
||||
- 0
|
||||
* - 0x04
|
||||
- Get Encoder Error
|
||||
- `encoder_error_rate_ms`
|
||||
- 0
|
||||
* - 0x1D
|
||||
- Get Controller Error
|
||||
- `controller_error_rate_ms`
|
||||
- 0
|
||||
* - 0x05
|
||||
- Get Sensorless Error
|
||||
- `sensorless_error_rate_ms`
|
||||
- 0
|
||||
* - 0x0A
|
||||
- Get Encoder Count
|
||||
- `encoder_count_rate_ms`
|
||||
- 0
|
||||
* - 0x14
|
||||
- Get Iq
|
||||
- `iq_rate_ms`
|
||||
- 0
|
||||
* - 0x15
|
||||
- Get Sensorless Estimates
|
||||
- `sensorless_rate_ms`
|
||||
- 0
|
||||
* - 0x17
|
||||
- Get Bus Voltage Current
|
||||
- `bus_vi_rate_ms`
|
||||
- 0
|
||||
|
||||
|
||||
.. ID | Name | Rate (ms)
|
||||
.. --: | :-- | :--
|
||||
.. 0x001 | ODrive Heartbeat Message | 100
|
||||
.. 0x009 | Encoder Estimates | 10
|
||||
|
||||
.. Command ID | Message Name
|
||||
.. :-- | :-- | :--
|
||||
.. 0x01 | `heartbeat_rate_ms` | Heartbeat
|
||||
.. 0x09 | `encoder_rate_ms` | Get Encoder Estimates
|
||||
.. 0x03 | `motor_error_rate_ms` | Get Motor Error
|
||||
.. 0x04 | `encoder_error_rate_ms` | Get Encoder Error
|
||||
.. 0x1D | `controller_error_rate_ms` | Get Controller Error
|
||||
.. 0x05 | `sensorless_error_rate_ms` | Get Sensorless Error
|
||||
.. 0x0A | `encoder_count_rate_ms` | Get Encoder Count
|
||||
.. 0x14 | `iq_rate_ms` | Get Iq
|
||||
.. 0x15 | `sensorless_rate_ms` | Get Sensorless Estimates
|
||||
.. 0x17 | `bus_vi_rate_ms` | Get Bus Voltage Current
|
||||
|
||||
These can be configured for each axis, see e.g. :code:`axis.config.can`.
|
||||
|
||||
|
||||
|
||||
@@ -2,16 +2,34 @@ CMD ID,Name,Sender,Signals,Start byte,Signal Type,Bits,Factor,Offset
|
||||
0x000,CANOpen NMT Message**,Master,-,-,-,-,-,-
|
||||
0x001,ODrive Heartbeat Message,Axis,"Axis Error
|
||||
Axis Current State
|
||||
Controller Status","0
|
||||
Motor Error Flag
|
||||
Encoder Error Flag
|
||||
Controller Error Flag
|
||||
Trajectory Done Flag","0
|
||||
4
|
||||
7","Unsigned Int
|
||||
5.0
|
||||
6.0
|
||||
7.0
|
||||
7.7","Unsigned Int
|
||||
Unsigned Int
|
||||
Bitfield","32
|
||||
Unsigned Int
|
||||
Unsigned Int
|
||||
Unsigned Int
|
||||
Unsigned Int","32
|
||||
8
|
||||
8","-
|
||||
1
|
||||
1
|
||||
1
|
||||
1","-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-","-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-"
|
||||
0x002,ODrive Estop Message,Master,-,-,-,-,-,-
|
||||
0x003,Get Motor Error*,Axis,Motor Error,0,Unsigned Int,64,1,0
|
||||
@@ -93,7 +111,13 @@ IEEE 754 Float","32
|
||||
1","0
|
||||
0"
|
||||
0x016,Reboot ODrive,Master***,-,-,-,-,-,-
|
||||
0x017,Get Vbus Voltage,Master***,Vbus Voltage,0,IEEE 754 Float,32,1,0
|
||||
0x017,Get Bus Voltage and Current,Master***,"Bus Voltage
|
||||
Bus Current","0
|
||||
4","IEEE 754 Float
|
||||
IEEE 754 Float","32
|
||||
32","1
|
||||
1","0
|
||||
0"
|
||||
0x018,Clear Errors,Master,-,-,-,-,-,-
|
||||
0x019,Set Linear Count,Master,Position,0,Signed Int,32,1,0
|
||||
0x01A,Set Position Gain,Master,Pos Gain,0,IEEE 754 Float,32,1,0
|
||||
@@ -104,4 +128,6 @@ IEEE 754 Float","32
|
||||
32","1
|
||||
1","0
|
||||
0"
|
||||
0x01C,Get ADC Voltage****,Master***,ADC Voltage,0,IEEE 754 Float,32,1,0
|
||||
0x01D,Get Controller Error*,Axis,Controller Error,0,Unsigned Int,32,1,0
|
||||
0x700,CANOpen Heartbeat Message**,Slave,-,-,-,-,-,-
|
||||
|
+176
-137
@@ -1,166 +1,184 @@
|
||||
import cantools
|
||||
from cantools.database import *
|
||||
from odrive.enums 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'], 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})
|
||||
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'])
|
||||
trajectoryDoneFlag = can.Signal("Trajectory_Done_Flag", 63, 1, 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,
|
||||
motorErrorFlag,
|
||||
encoderErrorFlag,
|
||||
controllerErrorFlag,
|
||||
trajectoryDoneFlag
|
||||
], 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'], choices={error.value: error.name for error in MotorError})
|
||||
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'], choices={error.value: error.name for error in EncoderError})
|
||||
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'], choices={error.value: error.name for error in SensorlessEstimatorError})
|
||||
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], choices={state.value: state.name for state in AxisState})
|
||||
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'], unit='rev')
|
||||
encoderVelEstimate = can.Signal("Vel_Estimate", 32, 32, is_float=True, receivers=['Master'], unit='rev/s')
|
||||
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'], unit='counts')
|
||||
encoderCountInCPR = can.Signal("Count_in_CPR", 32, 32, receivers=['Master'], unit='counts')
|
||||
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], 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})
|
||||
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], 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')
|
||||
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], unit='rev')
|
||||
inputTorqueFF = can.Signal("Input_Torque_FF", 32, 32, is_float=True, receivers=[newNode.name], unit='rev/s')
|
||||
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], unit='Nm')
|
||||
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], unit='rev/s')
|
||||
currentLimit = can.Signal("Current_Limit", 32, 32, is_float=True, receivers=[newNode.name], unit='A')
|
||||
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], unit='rev/s')
|
||||
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], unit='rev/s^2')
|
||||
trajDecelLim = can.Signal("Traj_Decel_Limit", 32, 32, is_float=True, receivers=[newNode.name], unit='rev/s^2')
|
||||
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], unit='Nm / (rev/s^2)')
|
||||
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'], unit='A')
|
||||
iqMeasured = can.Signal("Iq_Measured", 32, 32, is_float=True, receivers=['Master'], unit='A')
|
||||
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'], unit='rev')
|
||||
sensorlessVelEstimate = can.Signal("Sensorless_Vel_Estimate", 32, 32, is_float=True, receivers=['Master'], unit='rev/s')
|
||||
getSensorlessEstMsg = can.Message(0x015, "Get_Sensorless_Estimates", 8, [sensorlessPosEstimate, sensorlessVelEstimate], senders=[newNode.name])
|
||||
|
||||
# 0x017 - Get vbus Voltage
|
||||
vbusVoltage = cantools.database.can.Signal("Vbus_Voltage", 0, 32, is_float=True)
|
||||
getVbusVMsg = cantools.database.can.Message(0x017, "Get_Vbus_Voltage", 8, [vbusVoltage])
|
||||
# 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'], unit='V')
|
||||
busCurrent = can.Signal("Bus_Current", 32, 32, is_float=True, receivers=['Master'], unit='A')
|
||||
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], unit='counts')
|
||||
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], unit='(rev/s) / rev')
|
||||
setPosGainMsg = can.Message(0x01A, "Set_Pos_Gain", 8, [posGain], senders=['Master'])
|
||||
|
||||
db = cantools.database.can.Database(
|
||||
[
|
||||
# 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')
|
||||
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')
|
||||
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})
|
||||
controllerErrorMsg = can.Message(
|
||||
0x01D, "Get_Controller_Error", 8, [controllerError], senders=[newNode.name]
|
||||
)
|
||||
|
||||
axisMsgs = [
|
||||
heartbeatMsg,
|
||||
estopMsg,
|
||||
motorErrorMsg,
|
||||
encoderErrorMsg,
|
||||
sensorlessErrorMsg,
|
||||
@@ -180,14 +198,35 @@ db = cantools.database.can.Database(
|
||||
getIqMsg,
|
||||
getSensorlessEstMsg,
|
||||
rebootMsg,
|
||||
getVbusVMsg,
|
||||
getVbusVCMsg,
|
||||
clearErrorsMsg,
|
||||
setLinearCountMsg,
|
||||
setPosGainMsg,
|
||||
setVelGainsMsg
|
||||
setVelGainsMsg,
|
||||
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.6')
|
||||
|
||||
dump_file(db, "odrive-cansimple.dbc")
|
||||
db = load_file("odrive-cansimple.dbc")
|
||||
# print(db)
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
# To regenerate this file, nagivate to the top level of the ODrive repository and run:
|
||||
# python Firmware/interface_generator_stub.py --definitions Firmware/odrive-interface.yaml --template tools/enums_template.j2 --output tools/odrive/enums.py
|
||||
|
||||
import enum
|
||||
|
||||
[%- for _, enum in value_types.items() %]
|
||||
[%- if enum.is_enum %]
|
||||
|
||||
@@ -13,3 +15,11 @@
|
||||
[%- endif %]
|
||||
[%- endfor %]
|
||||
|
||||
[%- for _, enum in value_types.items() %]
|
||||
[%- if enum.is_enum %]
|
||||
class [[(enum.parent.name if enum.name in ['Error', 'Mode', 'Protocol'] else '') + enum.name]][% if enum.is_flags %](enum.IntFlag)[% else %](enum.Enum)[% endif %]:
|
||||
[%- for k, value in enum['values'].items() %]
|
||||
[[((k | to_macro_case)).ljust(40)]] = [% if enum.is_flags %]0x[['%08x' | format(value.value)]][% else %][[value.value]][% endif %]
|
||||
[%- endfor %]
|
||||
[%- endif %]
|
||||
[%- endfor %]
|
||||
|
||||
+983
-70
File diff suppressed because it is too large
Load Diff
@@ -3,6 +3,8 @@
|
||||
# To regenerate this file, nagivate to the top level of the ODrive repository and run:
|
||||
# python Firmware/interface_generator_stub.py --definitions Firmware/odrive-interface.yaml --template tools/enums_template.j2 --output tools/odrive/enums.py
|
||||
|
||||
import enum
|
||||
|
||||
# ODrive.GpioMode
|
||||
GPIO_MODE_DIGITAL = 0
|
||||
GPIO_MODE_DIGITAL_PULL_UP = 1
|
||||
@@ -165,3 +167,151 @@ ENCODER_ERROR_HALL_NOT_CALIBRATED_YET = 0x00000200
|
||||
SENSORLESS_ESTIMATOR_ERROR_NONE = 0x00000000
|
||||
SENSORLESS_ESTIMATOR_ERROR_UNSTABLE_GAIN = 0x00000001
|
||||
SENSORLESS_ESTIMATOR_ERROR_UNKNOWN_CURRENT_MEASUREMENT = 0x00000002
|
||||
class GpioMode(enum.Enum):
|
||||
DIGITAL = 0
|
||||
DIGITAL_PULL_UP = 1
|
||||
DIGITAL_PULL_DOWN = 2
|
||||
ANALOG_IN = 3
|
||||
UART_A = 4
|
||||
UART_B = 5
|
||||
UART_C = 6
|
||||
CAN_A = 7
|
||||
I2C_A = 8
|
||||
SPI_A = 9
|
||||
PWM = 10
|
||||
ENC0 = 11
|
||||
ENC1 = 12
|
||||
ENC2 = 13
|
||||
MECH_BRAKE = 14
|
||||
STATUS = 15
|
||||
class StreamProtocolType(enum.Enum):
|
||||
FIBRE = 0
|
||||
ASCII = 1
|
||||
STDOUT = 2
|
||||
ASCII_AND_STDOUT = 3
|
||||
class CanProtocol(enum.IntFlag):
|
||||
SIMPLE = 0x00000001
|
||||
class AxisState(enum.Enum):
|
||||
UNDEFINED = 0
|
||||
IDLE = 1
|
||||
STARTUP_SEQUENCE = 2
|
||||
FULL_CALIBRATION_SEQUENCE = 3
|
||||
MOTOR_CALIBRATION = 4
|
||||
ENCODER_INDEX_SEARCH = 6
|
||||
ENCODER_OFFSET_CALIBRATION = 7
|
||||
CLOSED_LOOP_CONTROL = 8
|
||||
LOCKIN_SPIN = 9
|
||||
ENCODER_DIR_FIND = 10
|
||||
HOMING = 11
|
||||
ENCODER_HALL_POLARITY_CALIBRATION = 12
|
||||
ENCODER_HALL_PHASE_CALIBRATION = 13
|
||||
class EncoderMode(enum.Enum):
|
||||
INCREMENTAL = 0
|
||||
HALL = 1
|
||||
SINCOS = 2
|
||||
SPI_ABS_CUI = 256
|
||||
SPI_ABS_AMS = 257
|
||||
SPI_ABS_AEAT = 258
|
||||
SPI_ABS_RLS = 259
|
||||
SPI_ABS_MA732 = 260
|
||||
class ControlMode(enum.Enum):
|
||||
VOLTAGE_CONTROL = 0
|
||||
TORQUE_CONTROL = 1
|
||||
VELOCITY_CONTROL = 2
|
||||
POSITION_CONTROL = 3
|
||||
class InputMode(enum.Enum):
|
||||
INACTIVE = 0
|
||||
PASSTHROUGH = 1
|
||||
VEL_RAMP = 2
|
||||
POS_FILTER = 3
|
||||
MIX_CHANNELS = 4
|
||||
TRAP_TRAJ = 5
|
||||
TORQUE_RAMP = 6
|
||||
MIRROR = 7
|
||||
TUNING = 8
|
||||
class MotorType(enum.Enum):
|
||||
HIGH_CURRENT = 0
|
||||
GIMBAL = 2
|
||||
ACIM = 3
|
||||
class ODriveError(enum.IntFlag):
|
||||
NONE = 0x00000000
|
||||
CONTROL_ITERATION_MISSED = 0x00000001
|
||||
DC_BUS_UNDER_VOLTAGE = 0x00000002
|
||||
DC_BUS_OVER_VOLTAGE = 0x00000004
|
||||
DC_BUS_OVER_REGEN_CURRENT = 0x00000008
|
||||
DC_BUS_OVER_CURRENT = 0x00000010
|
||||
BRAKE_DEADTIME_VIOLATION = 0x00000020
|
||||
BRAKE_DUTY_CYCLE_NAN = 0x00000040
|
||||
INVALID_BRAKE_RESISTANCE = 0x00000080
|
||||
class CanError(enum.IntFlag):
|
||||
NONE = 0x00000000
|
||||
DUPLICATE_CAN_IDS = 0x00000001
|
||||
class AxisError(enum.IntFlag):
|
||||
NONE = 0x00000000
|
||||
INVALID_STATE = 0x00000001
|
||||
MOTOR_FAILED = 0x00000040
|
||||
SENSORLESS_ESTIMATOR_FAILED = 0x00000080
|
||||
ENCODER_FAILED = 0x00000100
|
||||
CONTROLLER_FAILED = 0x00000200
|
||||
WATCHDOG_TIMER_EXPIRED = 0x00000800
|
||||
MIN_ENDSTOP_PRESSED = 0x00001000
|
||||
MAX_ENDSTOP_PRESSED = 0x00002000
|
||||
ESTOP_REQUESTED = 0x00004000
|
||||
HOMING_WITHOUT_ENDSTOP = 0x00020000
|
||||
OVER_TEMP = 0x00040000
|
||||
UNKNOWN_POSITION = 0x00080000
|
||||
class MotorError(enum.IntFlag):
|
||||
NONE = 0x00000000
|
||||
PHASE_RESISTANCE_OUT_OF_RANGE = 0x00000001
|
||||
PHASE_INDUCTANCE_OUT_OF_RANGE = 0x00000002
|
||||
DRV_FAULT = 0x00000008
|
||||
CONTROL_DEADLINE_MISSED = 0x00000010
|
||||
MODULATION_MAGNITUDE = 0x00000080
|
||||
CURRENT_SENSE_SATURATION = 0x00000400
|
||||
CURRENT_LIMIT_VIOLATION = 0x00001000
|
||||
MODULATION_IS_NAN = 0x00010000
|
||||
MOTOR_THERMISTOR_OVER_TEMP = 0x00020000
|
||||
FET_THERMISTOR_OVER_TEMP = 0x00040000
|
||||
TIMER_UPDATE_MISSED = 0x00080000
|
||||
CURRENT_MEASUREMENT_UNAVAILABLE = 0x00100000
|
||||
CONTROLLER_FAILED = 0x00200000
|
||||
I_BUS_OUT_OF_RANGE = 0x00400000
|
||||
BRAKE_RESISTOR_DISARMED = 0x00800000
|
||||
SYSTEM_LEVEL = 0x01000000
|
||||
BAD_TIMING = 0x02000000
|
||||
UNKNOWN_PHASE_ESTIMATE = 0x04000000
|
||||
UNKNOWN_PHASE_VEL = 0x08000000
|
||||
UNKNOWN_TORQUE = 0x10000000
|
||||
UNKNOWN_CURRENT_COMMAND = 0x20000000
|
||||
UNKNOWN_CURRENT_MEASUREMENT = 0x40000000
|
||||
UNKNOWN_VBUS_VOLTAGE = 0x80000000
|
||||
UNKNOWN_VOLTAGE_COMMAND = 0x100000000
|
||||
UNKNOWN_GAINS = 0x200000000
|
||||
CONTROLLER_INITIALIZING = 0x400000000
|
||||
UNBALANCED_PHASES = 0x800000000
|
||||
class ControllerError(enum.IntFlag):
|
||||
NONE = 0x00000000
|
||||
OVERSPEED = 0x00000001
|
||||
INVALID_INPUT_MODE = 0x00000002
|
||||
UNSTABLE_GAIN = 0x00000004
|
||||
INVALID_MIRROR_AXIS = 0x00000008
|
||||
INVALID_LOAD_ENCODER = 0x00000010
|
||||
INVALID_ESTIMATE = 0x00000020
|
||||
INVALID_CIRCULAR_RANGE = 0x00000040
|
||||
SPINOUT_DETECTED = 0x00000080
|
||||
class EncoderError(enum.IntFlag):
|
||||
NONE = 0x00000000
|
||||
UNSTABLE_GAIN = 0x00000001
|
||||
CPR_POLEPAIRS_MISMATCH = 0x00000002
|
||||
NO_RESPONSE = 0x00000004
|
||||
UNSUPPORTED_ENCODER_MODE = 0x00000008
|
||||
ILLEGAL_HALL_STATE = 0x00000010
|
||||
INDEX_NOT_FOUND_YET = 0x00000020
|
||||
ABS_SPI_TIMEOUT = 0x00000040
|
||||
ABS_SPI_COM_FAIL = 0x00000080
|
||||
ABS_SPI_NOT_READY = 0x00000100
|
||||
HALL_NOT_CALIBRATED_YET = 0x00000200
|
||||
class SensorlessEstimatorError(enum.IntFlag):
|
||||
NONE = 0x00000000
|
||||
UNSTABLE_GAIN = 0x00000001
|
||||
UNKNOWN_CURRENT_MEASUREMENT = 0x00000002
|
||||
Reference in New Issue
Block a user