mirror of
https://github.com/odriverobotics/ODrive.git
synced 2026-09-21 07:14:22 +08:00
absorb Arduino lib
This commit is contained in:
@@ -0,0 +1,197 @@
|
||||
|
||||
#include <Wire.h>
|
||||
#include "odrive.h"
|
||||
|
||||
|
||||
// See odrive.h for a description
|
||||
bool I2C_transaction(uint8_t slave_addr, const uint8_t * tx_buffer, size_t tx_length, uint8_t * rx_buffer, size_t rx_length) {
|
||||
// transmit
|
||||
if (tx_buffer) {
|
||||
Wire.beginTransmission(slave_addr);
|
||||
if (Wire.write(tx_buffer, tx_length) != tx_length)
|
||||
return false;
|
||||
bool should_stop = !rx_buffer;
|
||||
if (Wire.endTransmission(should_stop) != 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
// receive
|
||||
if (rx_buffer) {
|
||||
while(Wire.available()) Wire.read(); // flush input buffer
|
||||
if (Wire.requestFrom(slave_addr, (uint8_t)rx_length, (uint8_t)true /* stop after receiving */) != rx_length)
|
||||
return false;
|
||||
for (size_t i = 0; i < rx_length; ++i)
|
||||
rx_buffer[i] = Wire.read();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int set_and_save_configuration(uint8_t odrive_num, uint8_t axis_num) {
|
||||
bool success;
|
||||
success = odrive::clear_errors(odrive_num, axis_num);
|
||||
if (!success)
|
||||
return __LINE__;
|
||||
|
||||
// select hall effect mode
|
||||
bool user_config_loaded = false;
|
||||
success = odrive::read_property<odrive::USER_CONFIG_LOADED>(odrive_num, &user_config_loaded);
|
||||
if (!success)
|
||||
return __LINE__;
|
||||
if (user_config_loaded) {
|
||||
Serial.println("ODrive already configured");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// select hall effect mode
|
||||
success = odrive::write_axis_property<odrive::AXIS__ENCODER__CONFIG__MODE>(odrive_num, axis_num, 1);
|
||||
if (!success)
|
||||
return __LINE__;
|
||||
|
||||
// configure encoder counts per revolution (6 hall effect states * 12 pole pairs)
|
||||
success = odrive::write_axis_property<odrive::AXIS__ENCODER__CONFIG__CPR>(odrive_num, axis_num, 72);
|
||||
if (!success)
|
||||
return __LINE__;
|
||||
|
||||
// disable velocity integrator
|
||||
success = odrive::write_axis_property<odrive::AXIS__CONTROLLER__CONFIG__VEL_INTEGRATOR_GAIN>(odrive_num, axis_num, 0);
|
||||
if (!success)
|
||||
return __LINE__;
|
||||
|
||||
// select velocity control
|
||||
success = odrive::write_axis_property<odrive::AXIS__CONTROLLER__CONFIG__CONTROL_MODE>(odrive_num, axis_num, 2);
|
||||
if (!success)
|
||||
return __LINE__;
|
||||
|
||||
// set velocity controller P-gain
|
||||
success = odrive::write_axis_property<odrive::AXIS__CONTROLLER__CONFIG__VEL_GAIN>(odrive_num, axis_num, 0.005f);
|
||||
if (!success)
|
||||
return __LINE__;
|
||||
|
||||
// request state: motor calibration
|
||||
success = odrive::write_axis_property<odrive::AXIS__REQUESTED_STATE>(odrive_num, axis_num, 4);
|
||||
if (!success)
|
||||
return __LINE__;
|
||||
|
||||
delay(6000);
|
||||
|
||||
// check if the axis is in idle and no errors occurred
|
||||
if (!odrive::check_axis_state(odrive_num, axis_num, 1))
|
||||
return __LINE__;
|
||||
|
||||
// ensure that the motor calibration is considered valid after power cycle
|
||||
success = odrive::write_axis_property<odrive::AXIS__MOTOR__CONFIG__PRE_CALIBRATED>(odrive_num, axis_num, true);
|
||||
if (!success)
|
||||
return __LINE__;
|
||||
|
||||
// request state: encoder calibration
|
||||
success = odrive::write_axis_property<odrive::AXIS__REQUESTED_STATE>(odrive_num, axis_num, 7);
|
||||
if (!success)
|
||||
return __LINE__;
|
||||
|
||||
delay(12000);
|
||||
|
||||
// check if the axis is in idle and no errors occurred
|
||||
if (!odrive::check_axis_state(odrive_num, axis_num, 1))
|
||||
return __LINE__;
|
||||
|
||||
// ensure that the encoder calibration is considered valid after power cycle
|
||||
success = odrive::write_axis_property<odrive::AXIS__ENCODER__CONFIG__PRE_CALIBRATED>(odrive_num, axis_num, true);
|
||||
if (!success)
|
||||
return __LINE__;
|
||||
|
||||
// store the configuration to NVM
|
||||
// Caution: this operation is usually instantaneous but after every couple of hundred calls it will
|
||||
// take around 1 second (because a flash page needs to be erased).
|
||||
success = odrive::trigger<odrive::SAVE_CONFIGURATION>(odrive_num);
|
||||
if (!success)
|
||||
return __LINE__;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
byte odrive_num = 7;
|
||||
byte axis_num = 0;
|
||||
bool do_setup = true;
|
||||
|
||||
void setup() {
|
||||
Wire.begin(); // join i2c bus (address optional for master)
|
||||
Serial.begin(9600);
|
||||
Serial.println("Hello World!");
|
||||
|
||||
if (do_setup) {
|
||||
Serial.println("Starting ODrive setup...");
|
||||
int error_line = set_and_save_configuration(odrive_num, axis_num);
|
||||
if (error_line != 0) {
|
||||
Serial.print("ODrive setup failed at line ");
|
||||
Serial.print(error_line);
|
||||
Serial.println();
|
||||
return;
|
||||
}
|
||||
Serial.println("ODrive setup succeeded!");
|
||||
do_setup = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void loop() {
|
||||
bool success;
|
||||
delay(500);
|
||||
|
||||
success = odrive::check_axis_state(odrive_num, axis_num, 8);
|
||||
if (!success) {
|
||||
Serial.println("not in closed loop control - entering closed loop control");
|
||||
|
||||
// clear previous error state
|
||||
success = odrive::clear_errors(odrive_num, axis_num);
|
||||
if (!success) {
|
||||
Serial.println("could not enter closed loop control");
|
||||
return;
|
||||
}
|
||||
|
||||
// request velocity 0
|
||||
success = odrive::write_axis_property<odrive::AXIS__CONTROLLER__VEL_SETPOINT>(odrive_num, axis_num, 0);
|
||||
if (!success) {
|
||||
Serial.println("could not enter closed loop control");
|
||||
return;
|
||||
}
|
||||
|
||||
// request state: closed loop control
|
||||
success = odrive::write_axis_property<odrive::AXIS__REQUESTED_STATE>(odrive_num, axis_num, 8);
|
||||
if (!success) {
|
||||
Serial.println("could not enter closed loop control");
|
||||
return;
|
||||
}
|
||||
|
||||
success = odrive::check_axis_state(odrive_num, axis_num, 8);
|
||||
if (!success) {
|
||||
Serial.println("could not enter closed loop control");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
success = odrive::write_axis_property<odrive::AXIS__CONTROLLER__VEL_SETPOINT>(odrive_num, axis_num, 72 * 5);
|
||||
if (!success) {
|
||||
Serial.println("error");
|
||||
return;
|
||||
}
|
||||
|
||||
delay(500);
|
||||
|
||||
success = odrive::write_axis_property<odrive::AXIS__CONTROLLER__VEL_SETPOINT>(odrive_num, axis_num, -72 * 5);
|
||||
if (!success) {
|
||||
Serial.println("error");
|
||||
return;
|
||||
}
|
||||
|
||||
// print Vbus to show liveness
|
||||
float vbus;
|
||||
success = odrive::read_property<odrive::VBUS_VOLTAGE>(odrive_num, &vbus);
|
||||
if (!success) {
|
||||
Serial.println("error");
|
||||
return;
|
||||
}
|
||||
Serial.println(vbus);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
* ODrive I2C communication library
|
||||
* This file implements I2C communication with the ODrive.
|
||||
*
|
||||
* - Implement the C function I2C_transaction to provide low level I2C access.
|
||||
* - Use read_property<PropertyId>() to read properties from the ODrive.
|
||||
* - Use write_property<PropertyId>() to modify properties on the ODrive.
|
||||
* - Use trigger<PropertyId>() to trigger a function (such as reboot or save_configuration)
|
||||
* - Use endpoint_type_t<PropertyId> to retrieve the underlying type
|
||||
* of a given property.
|
||||
* - Refer to PropertyId for a list of available properties.
|
||||
*
|
||||
* To regenerate the interface definitions, flash an ODrive with
|
||||
* the new firmware, connect it to your PC via USB and then run
|
||||
* ../tools/odrivetool generate-code --output [path to odrive_endpoints.h]
|
||||
* This step can be done with any ODrive, it doesn't have to be the
|
||||
* one that you'll be controlling over I2C.
|
||||
*/
|
||||
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "odrive_endpoints.h"
|
||||
|
||||
#ifdef __AVR__
|
||||
// AVR-GCC doesn't ship with the STL, so we use our own little excerpt
|
||||
#include "type_traits.h"
|
||||
#else
|
||||
#include <type_traits>
|
||||
#endif
|
||||
|
||||
|
||||
extern "C" {
|
||||
|
||||
/* @brief Send and receive data to/from an I2C slave
|
||||
*
|
||||
* This function carries out the following sequence:
|
||||
* 1. generate a START condition
|
||||
* 2. if the tx_buffer is not null:
|
||||
* a. send 7-bit slave address (with the LSB 0)
|
||||
* b. send all bytes in the tx_buffer
|
||||
* 3. if both tx_buffer and rx_buffer are not null, generate a REPEATED START condition
|
||||
* 4. if the rx_buffer is not null:
|
||||
* a. send 7-bit slave address (with the LSB 1)
|
||||
* b. read rx_length bytes into rx_buffer
|
||||
* 5. send STOP condition
|
||||
*
|
||||
* @param slave_addr: 7-bit slave address (the MSB is ignored)
|
||||
* @return true if all data was transmitted and received as requested by the caller, false otherwise
|
||||
*/
|
||||
bool I2C_transaction(uint8_t slave_addr, const uint8_t * tx_buffer, size_t tx_length, uint8_t * rx_buffer, size_t rx_length);
|
||||
|
||||
}
|
||||
|
||||
|
||||
namespace odrive {
|
||||
static constexpr const uint8_t i2c_addr = (0xD << 3); // write: 1101xxx0, read: 1101xxx1
|
||||
|
||||
template<typename T>
|
||||
using bit_width = std::integral_constant<unsigned int, CHAR_BIT * sizeof(T)>;
|
||||
|
||||
template<typename T>
|
||||
using byte_width = std::integral_constant<unsigned int, (bit_width<T>::value + 7) / 8>;
|
||||
|
||||
|
||||
template<unsigned int IBitSize>
|
||||
struct unsigned_int_of_size;
|
||||
|
||||
template<> struct unsigned_int_of_size<32> { typedef uint32_t type; };
|
||||
|
||||
|
||||
template<typename T>
|
||||
typename std::enable_if<std::is_integral<T>::value, T>::type
|
||||
read_le(const uint8_t buffer[byte_width<T>::value]) {
|
||||
T value = 0;
|
||||
for (size_t i = 0; i < byte_width<T>::value; ++i)
|
||||
value |= (static_cast<T>(buffer[i]) << (i << 3));
|
||||
return value;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename std::enable_if<std::is_floating_point<T>::value, T>::type
|
||||
read_le(const uint8_t buffer[]) {
|
||||
using T_Int = typename unsigned_int_of_size<bit_width<T>::value>::type;
|
||||
T_Int value = read_le<T_Int>(buffer);
|
||||
return *reinterpret_cast<T*>(&value);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename std::enable_if<std::is_integral<T>::value, void>::type
|
||||
write_le(uint8_t buffer[byte_width<T>::value], T value) {
|
||||
for (size_t i = 0; i < byte_width<T>::value; ++i)
|
||||
buffer[i] = (value >> (i << 3)) & 0xff;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename std::enable_if<std::is_floating_point<T>::value, T>::type
|
||||
write_le(uint8_t buffer[byte_width<T>::value], T value) {
|
||||
using T_Int = typename unsigned_int_of_size<bit_width<T>::value>::type;
|
||||
write_le<T_Int>(buffer, *reinterpret_cast<T_Int*>(&value));
|
||||
}
|
||||
|
||||
/* @brief Read from an endpoint on the ODrive.
|
||||
* To read from an axis specific endpoint use read_axis_property() instead.
|
||||
*
|
||||
* Usage example:
|
||||
* float val;
|
||||
* success = odrive::read_property<odrive::VBUS_VOLTAGE>(0, &val);
|
||||
*
|
||||
* @param num Selects the ODrive. For instance the value 4 selects
|
||||
* the ODrive that has [A2, A1, A0] connected to [VCC, GND, GND].
|
||||
* @return true if the I2C transaction succeeded, false otherwise
|
||||
*/
|
||||
template<int IPropertyId>
|
||||
bool read_property(uint8_t num, endpoint_type_t<IPropertyId>* value, uint16_t address = IPropertyId) {
|
||||
uint8_t i2c_tx_buffer[4];
|
||||
write_le<uint16_t>(i2c_tx_buffer, address);
|
||||
write_le<uint16_t>(i2c_tx_buffer + sizeof(i2c_tx_buffer) - 2, json_crc);
|
||||
uint8_t i2c_rx_buffer[byte_width<endpoint_type_t<IPropertyId>>::value];
|
||||
if (!I2C_transaction(i2c_addr + num,
|
||||
i2c_tx_buffer, sizeof(i2c_tx_buffer),
|
||||
i2c_rx_buffer, sizeof(i2c_rx_buffer)))
|
||||
return false;
|
||||
if (value)
|
||||
*value = read_le<endpoint_type_t<IPropertyId>>(i2c_rx_buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* @brief Write to an endpoint on the ODrive.
|
||||
* To write to an axis specific endpoint use write_axis_property() instead.
|
||||
*
|
||||
* Usage example:
|
||||
* success = odrive::write_property<odrive::TEST_PROPERTY>(0, 42);
|
||||
*
|
||||
* @param num Selects the ODrive. For instance the value 4 selects
|
||||
* the ODrive that has [A2, A1, A0] connected to [VCC, GND, GND].
|
||||
* @return true if the I2C transaction succeeded, false otherwise
|
||||
*/
|
||||
template<int IPropertyId>
|
||||
bool write_property(uint8_t num, endpoint_type_t<IPropertyId> value, uint16_t address = IPropertyId) {
|
||||
uint8_t i2c_tx_buffer[4 + byte_width<endpoint_type_t<IPropertyId>>::value];
|
||||
write_le<uint16_t>(i2c_tx_buffer, address);
|
||||
write_le<endpoint_type_t<IPropertyId>>(i2c_tx_buffer + 2, value);
|
||||
write_le<uint16_t>(i2c_tx_buffer + sizeof(i2c_tx_buffer) - 2, json_crc);
|
||||
return I2C_transaction(i2c_addr + num, i2c_tx_buffer, sizeof(i2c_tx_buffer), nullptr, 0);
|
||||
}
|
||||
|
||||
/* @brief Trigger an parameter-less function on the ODrive
|
||||
*
|
||||
* Usage example:
|
||||
* success = odrive::trigger<odrive::SAVE_CONFIGURATION>(0);
|
||||
*
|
||||
* @param num Selects the ODrive. For instance the value 4 selects
|
||||
* the ODrive that has [A2, A1, A0] connected to [VCC, GND, GND].
|
||||
* @return true if the I2C transaction succeeded, false otherwise
|
||||
*/
|
||||
template<int IPropertyId,
|
||||
typename = typename std::enable_if<std::is_void<endpoint_type_t<IPropertyId>>::value>::type>
|
||||
bool trigger(uint8_t num, uint16_t address = IPropertyId) {
|
||||
uint8_t i2c_tx_buffer[4];
|
||||
write_le<uint16_t>(i2c_tx_buffer, address);
|
||||
write_le<uint16_t>(i2c_tx_buffer + sizeof(i2c_tx_buffer) - 2, json_crc);
|
||||
return I2C_transaction(i2c_addr + num, i2c_tx_buffer, sizeof(i2c_tx_buffer), nullptr, 0);
|
||||
}
|
||||
|
||||
template<int IPropertyId>
|
||||
bool read_axis_property(uint8_t num, uint8_t axis, endpoint_type_t<IPropertyId>* value) {
|
||||
return read_property<IPropertyId>(num, value, IPropertyId + axis * per_axis_offset);
|
||||
}
|
||||
|
||||
template<int IPropertyId>
|
||||
bool write_axis_property(uint8_t num, uint8_t axis, endpoint_type_t<IPropertyId> value) {
|
||||
return write_property<IPropertyId>(num, value, IPropertyId + axis * per_axis_offset);
|
||||
}
|
||||
|
||||
|
||||
/* @brief Checks if the axis is in the requested state and the error register is clear */
|
||||
bool check_axis_state(uint8_t num, uint8_t axis, uint8_t state) {
|
||||
endpoint_type_t<odrive::AXIS__CURRENT_STATE> observed_state = 0;
|
||||
endpoint_type_t<odrive::AXIS__ERROR> observed_error = 0;
|
||||
if (!read_axis_property<odrive::AXIS__CURRENT_STATE>(num, axis, &observed_state))
|
||||
return false;
|
||||
if (!read_axis_property<odrive::AXIS__ERROR>(num, axis, &observed_error))
|
||||
return false;
|
||||
return (observed_error == 0) && (observed_state == state);
|
||||
}
|
||||
|
||||
/* @brief Clears any error state of the specified axis */
|
||||
bool clear_errors(uint8_t num, uint8_t axis) {
|
||||
if (!write_axis_property<odrive::AXIS__ERROR>(num, axis, 0))
|
||||
return false;
|
||||
if (!write_axis_property<odrive::AXIS__MOTOR__ERROR>(num, axis, 0))
|
||||
return false;
|
||||
if (!write_axis_property<odrive::AXIS__ENCODER__ERROR>(num, axis, 0))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,299 @@
|
||||
/*
|
||||
* This file was autogenerated using the "odrivetool generate-code" feature.
|
||||
*
|
||||
* The file matches a specific firmware version. If you add/remove/rename any
|
||||
* properties exposed by the ODrive, this file needs to be regenerated, otherwise
|
||||
* the ODrive will ignore all commands.
|
||||
*/
|
||||
|
||||
#ifndef __ODRIVE_ENDPOINTS_HPP
|
||||
#define __ODRIVE_ENDPOINTS_HPP
|
||||
|
||||
|
||||
namespace odrive {
|
||||
|
||||
static constexpr const uint16_t json_crc = 0xbe97;
|
||||
|
||||
static constexpr const uint16_t per_axis_offset = 101;
|
||||
|
||||
enum {
|
||||
VBUS_VOLTAGE = 1,
|
||||
SERIAL_NUMBER = 2,
|
||||
HW_VERSION_MAJOR = 3,
|
||||
HW_VERSION_MINOR = 4,
|
||||
HW_VERSION_VARIANT = 5,
|
||||
FW_VERSION_MAJOR = 6,
|
||||
FW_VERSION_MINOR = 7,
|
||||
FW_VERSION_REVISION = 8,
|
||||
FW_VERSION_UNRELEASED = 9,
|
||||
USER_CONFIG_LOADED = 10,
|
||||
BRAKE_RESISTOR_ARMED = 11,
|
||||
SYSTEM_STATS__UPTIME = 12,
|
||||
SYSTEM_STATS__MIN_HEAP_SPACE = 13,
|
||||
SYSTEM_STATS__MIN_STACK_SPACE_AXIS0 = 14,
|
||||
SYSTEM_STATS__MIN_STACK_SPACE_AXIS1 = 15,
|
||||
SYSTEM_STATS__MIN_STACK_SPACE_COMMS = 16,
|
||||
SYSTEM_STATS__MIN_STACK_SPACE_USB = 17,
|
||||
SYSTEM_STATS__MIN_STACK_SPACE_UART = 18,
|
||||
SYSTEM_STATS__MIN_STACK_SPACE_USB_IRQ = 19,
|
||||
SYSTEM_STATS__MIN_STACK_SPACE_STARTUP = 20,
|
||||
SYSTEM_STATS__USB__RX_CNT = 21,
|
||||
SYSTEM_STATS__USB__TX_CNT = 22,
|
||||
SYSTEM_STATS__USB__TX_OVERRUN_CNT = 23,
|
||||
SYSTEM_STATS__I2C__ADDR = 24,
|
||||
SYSTEM_STATS__I2C__ADDR_MATCH_CNT = 25,
|
||||
SYSTEM_STATS__I2C__RX_CNT = 26,
|
||||
SYSTEM_STATS__I2C__ERROR_CNT = 27,
|
||||
CONFIG__BRAKE_RESISTANCE = 28,
|
||||
CONFIG__ENABLE_UART = 29,
|
||||
CONFIG__ENABLE_I2C_INSTEAD_OF_CAN = 30,
|
||||
CONFIG__DC_BUS_UNDERVOLTAGE_TRIP_LEVEL = 31,
|
||||
CONFIG__DC_BUS_OVERVOLTAGE_TRIP_LEVEL = 32,
|
||||
TEST_PROPERTY = 235,
|
||||
ADC_GPIO1 = 242,
|
||||
ADC_GPIO2 = 243,
|
||||
SAVE_CONFIGURATION = 244,
|
||||
ERASE_CONFIGURATION = 245,
|
||||
REBOOT = 246,
|
||||
ENTER_DFU_MODE = 247,
|
||||
|
||||
// Per-Axis endpoints (to be used with read_axis_property and write_axis_property)
|
||||
AXIS__ERROR = 33,
|
||||
AXIS__ENABLE_STEP_DIR = 34,
|
||||
AXIS__CURRENT_STATE = 35,
|
||||
AXIS__REQUESTED_STATE = 36,
|
||||
AXIS__LOOP_COUNTER = 37,
|
||||
AXIS__CONFIG__STARTUP_MOTOR_CALIBRATION = 38,
|
||||
AXIS__CONFIG__STARTUP_ENCODER_INDEX_SEARCH = 39,
|
||||
AXIS__CONFIG__STARTUP_ENCODER_OFFSET_CALIBRATION = 40,
|
||||
AXIS__CONFIG__STARTUP_CLOSED_LOOP_CONTROL = 41,
|
||||
AXIS__CONFIG__STARTUP_SENSORLESS_CONTROL = 42,
|
||||
AXIS__CONFIG__ENABLE_STEP_DIR = 43,
|
||||
AXIS__CONFIG__COUNTS_PER_STEP = 44,
|
||||
AXIS__CONFIG__RAMP_UP_TIME = 45,
|
||||
AXIS__CONFIG__RAMP_UP_DISTANCE = 46,
|
||||
AXIS__CONFIG__SPIN_UP_CURRENT = 47,
|
||||
AXIS__CONFIG__SPIN_UP_ACCELERATION = 48,
|
||||
AXIS__CONFIG__SPIN_UP_TARGET_VEL = 49,
|
||||
AXIS__MOTOR__ERROR = 50,
|
||||
AXIS__MOTOR__ARMED_STATE = 51,
|
||||
AXIS__MOTOR__IS_CALIBRATED = 52,
|
||||
AXIS__MOTOR__CURRENT_MEAS_PHB = 53,
|
||||
AXIS__MOTOR__CURRENT_MEAS_PHC = 54,
|
||||
AXIS__MOTOR__DC_CALIB_PHB = 55,
|
||||
AXIS__MOTOR__DC_CALIB_PHC = 56,
|
||||
AXIS__MOTOR__PHASE_CURRENT_REV_GAIN = 57,
|
||||
AXIS__MOTOR__CURRENT_CONTROL__P_GAIN = 58,
|
||||
AXIS__MOTOR__CURRENT_CONTROL__I_GAIN = 59,
|
||||
AXIS__MOTOR__CURRENT_CONTROL__V_CURRENT_CONTROL_INTEGRAL_D = 60,
|
||||
AXIS__MOTOR__CURRENT_CONTROL__V_CURRENT_CONTROL_INTEGRAL_Q = 61,
|
||||
AXIS__MOTOR__CURRENT_CONTROL__IBUS = 62,
|
||||
AXIS__MOTOR__CURRENT_CONTROL__FINAL_V_ALPHA = 63,
|
||||
AXIS__MOTOR__CURRENT_CONTROL__FINAL_V_BETA = 64,
|
||||
AXIS__MOTOR__CURRENT_CONTROL__IQ_SETPOINT = 65,
|
||||
AXIS__MOTOR__CURRENT_CONTROL__IQ_MEASURED = 66,
|
||||
AXIS__MOTOR__CURRENT_CONTROL__MAX_ALLOWED_CURRENT = 67,
|
||||
AXIS__MOTOR__GATE_DRIVER__DRV_FAULT = 68,
|
||||
AXIS__MOTOR__TIMING_LOG__TIMING_LOG_GENERAL = 69,
|
||||
AXIS__MOTOR__TIMING_LOG__TIMING_LOG_ADC_CB_I = 70,
|
||||
AXIS__MOTOR__TIMING_LOG__TIMING_LOG_ADC_CB_DC = 71,
|
||||
AXIS__MOTOR__TIMING_LOG__TIMING_LOG_MEAS_R = 72,
|
||||
AXIS__MOTOR__TIMING_LOG__TIMING_LOG_MEAS_L = 73,
|
||||
AXIS__MOTOR__TIMING_LOG__TIMING_LOG_ENC_CALIB = 74,
|
||||
AXIS__MOTOR__TIMING_LOG__TIMING_LOG_IDX_SEARCH = 75,
|
||||
AXIS__MOTOR__TIMING_LOG__TIMING_LOG_FOC_VOLTAGE = 76,
|
||||
AXIS__MOTOR__TIMING_LOG__TIMING_LOG_FOC_CURRENT = 77,
|
||||
AXIS__MOTOR__CONFIG__PRE_CALIBRATED = 78,
|
||||
AXIS__MOTOR__CONFIG__POLE_PAIRS = 79,
|
||||
AXIS__MOTOR__CONFIG__CALIBRATION_CURRENT = 80,
|
||||
AXIS__MOTOR__CONFIG__RESISTANCE_CALIB_MAX_VOLTAGE = 81,
|
||||
AXIS__MOTOR__CONFIG__PHASE_INDUCTANCE = 82,
|
||||
AXIS__MOTOR__CONFIG__PHASE_RESISTANCE = 83,
|
||||
AXIS__MOTOR__CONFIG__DIRECTION = 84,
|
||||
AXIS__MOTOR__CONFIG__MOTOR_TYPE = 85,
|
||||
AXIS__MOTOR__CONFIG__CURRENT_LIM = 86,
|
||||
AXIS__CONTROLLER__POS_SETPOINT = 87,
|
||||
AXIS__CONTROLLER__VEL_SETPOINT = 88,
|
||||
AXIS__CONTROLLER__VEL_INTEGRATOR_CURRENT = 89,
|
||||
AXIS__CONTROLLER__CURRENT_SETPOINT = 90,
|
||||
AXIS__CONTROLLER__CONFIG__CONTROL_MODE = 91,
|
||||
AXIS__CONTROLLER__CONFIG__POS_GAIN = 92,
|
||||
AXIS__CONTROLLER__CONFIG__VEL_GAIN = 93,
|
||||
AXIS__CONTROLLER__CONFIG__VEL_INTEGRATOR_GAIN = 94,
|
||||
AXIS__CONTROLLER__CONFIG__VEL_LIMIT = 95,
|
||||
AXIS__CONTROLLER__START_ANTICOGGING_CALIBRATION = 105,
|
||||
AXIS__ENCODER__ERROR = 106,
|
||||
AXIS__ENCODER__IS_READY = 107,
|
||||
AXIS__ENCODER__INDEX_FOUND = 108,
|
||||
AXIS__ENCODER__SHADOW_COUNT = 109,
|
||||
AXIS__ENCODER__COUNT_IN_CPR = 110,
|
||||
AXIS__ENCODER__OFFSET = 111,
|
||||
AXIS__ENCODER__INTERPOLATION = 112,
|
||||
AXIS__ENCODER__PHASE = 113,
|
||||
AXIS__ENCODER__POS_ESTIMATE = 114,
|
||||
AXIS__ENCODER__POS_CPR = 115,
|
||||
AXIS__ENCODER__HALL_STATE = 116,
|
||||
AXIS__ENCODER__PLL_VEL = 117,
|
||||
AXIS__ENCODER__PLL_KP = 118,
|
||||
AXIS__ENCODER__PLL_KI = 119,
|
||||
AXIS__ENCODER__CONFIG__MODE = 120,
|
||||
AXIS__ENCODER__CONFIG__USE_INDEX = 121,
|
||||
AXIS__ENCODER__CONFIG__PRE_CALIBRATED = 122,
|
||||
AXIS__ENCODER__CONFIG__IDX_SEARCH_SPEED = 123,
|
||||
AXIS__ENCODER__CONFIG__CPR = 124,
|
||||
AXIS__ENCODER__CONFIG__OFFSET = 125,
|
||||
AXIS__ENCODER__CONFIG__OFFSET_FLOAT = 126,
|
||||
AXIS__ENCODER__CONFIG__CALIB_RANGE = 127,
|
||||
AXIS__SENSORLESS_ESTIMATOR__ERROR = 128,
|
||||
AXIS__SENSORLESS_ESTIMATOR__PHASE = 129,
|
||||
AXIS__SENSORLESS_ESTIMATOR__PLL_POS = 130,
|
||||
AXIS__SENSORLESS_ESTIMATOR__PLL_VEL = 131,
|
||||
AXIS__SENSORLESS_ESTIMATOR__PLL_KP = 132,
|
||||
AXIS__SENSORLESS_ESTIMATOR__PLL_KI = 133,
|
||||
};
|
||||
|
||||
template<int I>
|
||||
struct endpoint_type;
|
||||
|
||||
template<> struct endpoint_type<VBUS_VOLTAGE> { typedef float type; };
|
||||
template<> struct endpoint_type<SERIAL_NUMBER> { typedef uint64_t type; };
|
||||
template<> struct endpoint_type<HW_VERSION_MAJOR> { typedef uint8_t type; };
|
||||
template<> struct endpoint_type<HW_VERSION_MINOR> { typedef uint8_t type; };
|
||||
template<> struct endpoint_type<HW_VERSION_VARIANT> { typedef uint8_t type; };
|
||||
template<> struct endpoint_type<FW_VERSION_MAJOR> { typedef uint8_t type; };
|
||||
template<> struct endpoint_type<FW_VERSION_MINOR> { typedef uint8_t type; };
|
||||
template<> struct endpoint_type<FW_VERSION_REVISION> { typedef uint8_t type; };
|
||||
template<> struct endpoint_type<FW_VERSION_UNRELEASED> { typedef uint8_t type; };
|
||||
template<> struct endpoint_type<USER_CONFIG_LOADED> { typedef bool type; };
|
||||
template<> struct endpoint_type<BRAKE_RESISTOR_ARMED> { typedef bool type; };
|
||||
template<> struct endpoint_type<SYSTEM_STATS__UPTIME> { typedef uint32_t type; };
|
||||
template<> struct endpoint_type<SYSTEM_STATS__MIN_HEAP_SPACE> { typedef uint32_t type; };
|
||||
template<> struct endpoint_type<SYSTEM_STATS__MIN_STACK_SPACE_AXIS0> { typedef uint32_t type; };
|
||||
template<> struct endpoint_type<SYSTEM_STATS__MIN_STACK_SPACE_AXIS1> { typedef uint32_t type; };
|
||||
template<> struct endpoint_type<SYSTEM_STATS__MIN_STACK_SPACE_COMMS> { typedef uint32_t type; };
|
||||
template<> struct endpoint_type<SYSTEM_STATS__MIN_STACK_SPACE_USB> { typedef uint32_t type; };
|
||||
template<> struct endpoint_type<SYSTEM_STATS__MIN_STACK_SPACE_UART> { typedef uint32_t type; };
|
||||
template<> struct endpoint_type<SYSTEM_STATS__MIN_STACK_SPACE_USB_IRQ> { typedef uint32_t type; };
|
||||
template<> struct endpoint_type<SYSTEM_STATS__MIN_STACK_SPACE_STARTUP> { typedef uint32_t type; };
|
||||
template<> struct endpoint_type<SYSTEM_STATS__USB__RX_CNT> { typedef uint32_t type; };
|
||||
template<> struct endpoint_type<SYSTEM_STATS__USB__TX_CNT> { typedef uint32_t type; };
|
||||
template<> struct endpoint_type<SYSTEM_STATS__USB__TX_OVERRUN_CNT> { typedef uint32_t type; };
|
||||
template<> struct endpoint_type<SYSTEM_STATS__I2C__ADDR> { typedef uint8_t type; };
|
||||
template<> struct endpoint_type<SYSTEM_STATS__I2C__ADDR_MATCH_CNT> { typedef uint32_t type; };
|
||||
template<> struct endpoint_type<SYSTEM_STATS__I2C__RX_CNT> { typedef uint32_t type; };
|
||||
template<> struct endpoint_type<SYSTEM_STATS__I2C__ERROR_CNT> { typedef uint32_t type; };
|
||||
template<> struct endpoint_type<CONFIG__BRAKE_RESISTANCE> { typedef float type; };
|
||||
template<> struct endpoint_type<CONFIG__ENABLE_UART> { typedef bool type; };
|
||||
template<> struct endpoint_type<CONFIG__ENABLE_I2C_INSTEAD_OF_CAN> { typedef bool type; };
|
||||
template<> struct endpoint_type<CONFIG__DC_BUS_UNDERVOLTAGE_TRIP_LEVEL> { typedef float type; };
|
||||
template<> struct endpoint_type<CONFIG__DC_BUS_OVERVOLTAGE_TRIP_LEVEL> { typedef float type; };
|
||||
template<> struct endpoint_type<TEST_PROPERTY> { typedef uint32_t type; };
|
||||
template<> struct endpoint_type<ADC_GPIO1> { typedef uint16_t type; };
|
||||
template<> struct endpoint_type<ADC_GPIO2> { typedef uint16_t type; };
|
||||
template<> struct endpoint_type<SAVE_CONFIGURATION> { typedef void type; };
|
||||
template<> struct endpoint_type<ERASE_CONFIGURATION> { typedef void type; };
|
||||
template<> struct endpoint_type<REBOOT> { typedef void type; };
|
||||
template<> struct endpoint_type<ENTER_DFU_MODE> { typedef void type; };
|
||||
|
||||
|
||||
// Per-axis endpoints
|
||||
template<> struct endpoint_type<AXIS__ERROR> { typedef uint16_t type; };
|
||||
template<> struct endpoint_type<AXIS__ENABLE_STEP_DIR> { typedef bool type; };
|
||||
template<> struct endpoint_type<AXIS__CURRENT_STATE> { typedef uint8_t type; };
|
||||
template<> struct endpoint_type<AXIS__REQUESTED_STATE> { typedef uint8_t type; };
|
||||
template<> struct endpoint_type<AXIS__LOOP_COUNTER> { typedef uint32_t type; };
|
||||
template<> struct endpoint_type<AXIS__CONFIG__STARTUP_MOTOR_CALIBRATION> { typedef bool type; };
|
||||
template<> struct endpoint_type<AXIS__CONFIG__STARTUP_ENCODER_INDEX_SEARCH> { typedef bool type; };
|
||||
template<> struct endpoint_type<AXIS__CONFIG__STARTUP_ENCODER_OFFSET_CALIBRATION> { typedef bool type; };
|
||||
template<> struct endpoint_type<AXIS__CONFIG__STARTUP_CLOSED_LOOP_CONTROL> { typedef bool type; };
|
||||
template<> struct endpoint_type<AXIS__CONFIG__STARTUP_SENSORLESS_CONTROL> { typedef bool type; };
|
||||
template<> struct endpoint_type<AXIS__CONFIG__ENABLE_STEP_DIR> { typedef bool type; };
|
||||
template<> struct endpoint_type<AXIS__CONFIG__COUNTS_PER_STEP> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__CONFIG__RAMP_UP_TIME> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__CONFIG__RAMP_UP_DISTANCE> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__CONFIG__SPIN_UP_CURRENT> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__CONFIG__SPIN_UP_ACCELERATION> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__CONFIG__SPIN_UP_TARGET_VEL> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__ERROR> { typedef uint16_t type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__ARMED_STATE> { typedef uint8_t type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__IS_CALIBRATED> { typedef bool type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__CURRENT_MEAS_PHB> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__CURRENT_MEAS_PHC> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__DC_CALIB_PHB> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__DC_CALIB_PHC> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__PHASE_CURRENT_REV_GAIN> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__CURRENT_CONTROL__P_GAIN> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__CURRENT_CONTROL__I_GAIN> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__CURRENT_CONTROL__V_CURRENT_CONTROL_INTEGRAL_D> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__CURRENT_CONTROL__V_CURRENT_CONTROL_INTEGRAL_Q> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__CURRENT_CONTROL__IBUS> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__CURRENT_CONTROL__FINAL_V_ALPHA> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__CURRENT_CONTROL__FINAL_V_BETA> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__CURRENT_CONTROL__IQ_SETPOINT> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__CURRENT_CONTROL__IQ_MEASURED> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__CURRENT_CONTROL__MAX_ALLOWED_CURRENT> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__GATE_DRIVER__DRV_FAULT> { typedef uint16_t type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__TIMING_LOG__TIMING_LOG_GENERAL> { typedef uint16_t type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__TIMING_LOG__TIMING_LOG_ADC_CB_I> { typedef uint16_t type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__TIMING_LOG__TIMING_LOG_ADC_CB_DC> { typedef uint16_t type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__TIMING_LOG__TIMING_LOG_MEAS_R> { typedef uint16_t type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__TIMING_LOG__TIMING_LOG_MEAS_L> { typedef uint16_t type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__TIMING_LOG__TIMING_LOG_ENC_CALIB> { typedef uint16_t type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__TIMING_LOG__TIMING_LOG_IDX_SEARCH> { typedef uint16_t type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__TIMING_LOG__TIMING_LOG_FOC_VOLTAGE> { typedef uint16_t type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__TIMING_LOG__TIMING_LOG_FOC_CURRENT> { typedef uint16_t type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__CONFIG__PRE_CALIBRATED> { typedef bool type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__CONFIG__POLE_PAIRS> { typedef int32_t type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__CONFIG__CALIBRATION_CURRENT> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__CONFIG__RESISTANCE_CALIB_MAX_VOLTAGE> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__CONFIG__PHASE_INDUCTANCE> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__CONFIG__PHASE_RESISTANCE> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__CONFIG__DIRECTION> { typedef int32_t type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__CONFIG__MOTOR_TYPE> { typedef uint8_t type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__CONFIG__CURRENT_LIM> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__CONTROLLER__POS_SETPOINT> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__CONTROLLER__VEL_SETPOINT> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__CONTROLLER__VEL_INTEGRATOR_CURRENT> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__CONTROLLER__CURRENT_SETPOINT> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__CONTROLLER__CONFIG__CONTROL_MODE> { typedef uint8_t type; };
|
||||
template<> struct endpoint_type<AXIS__CONTROLLER__CONFIG__POS_GAIN> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__CONTROLLER__CONFIG__VEL_GAIN> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__CONTROLLER__CONFIG__VEL_INTEGRATOR_GAIN> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__CONTROLLER__CONFIG__VEL_LIMIT> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__CONTROLLER__START_ANTICOGGING_CALIBRATION> { typedef void type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__ERROR> { typedef uint8_t type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__IS_READY> { typedef bool type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__INDEX_FOUND> { typedef bool type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__SHADOW_COUNT> { typedef int32_t type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__COUNT_IN_CPR> { typedef int32_t type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__OFFSET> { typedef int32_t type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__INTERPOLATION> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__PHASE> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__POS_ESTIMATE> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__POS_CPR> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__HALL_STATE> { typedef uint8_t type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__PLL_VEL> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__PLL_KP> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__PLL_KI> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__CONFIG__MODE> { typedef uint8_t type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__CONFIG__USE_INDEX> { typedef bool type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__CONFIG__PRE_CALIBRATED> { typedef bool type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__CONFIG__IDX_SEARCH_SPEED> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__CONFIG__CPR> { typedef int32_t type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__CONFIG__OFFSET> { typedef int32_t type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__CONFIG__OFFSET_FLOAT> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__CONFIG__CALIB_RANGE> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__SENSORLESS_ESTIMATOR__ERROR> { typedef uint8_t type; };
|
||||
template<> struct endpoint_type<AXIS__SENSORLESS_ESTIMATOR__PHASE> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__SENSORLESS_ESTIMATOR__PLL_POS> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__SENSORLESS_ESTIMATOR__PLL_VEL> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__SENSORLESS_ESTIMATOR__PLL_KP> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__SENSORLESS_ESTIMATOR__PLL_KI> { typedef float type; };
|
||||
|
||||
|
||||
template<int I>
|
||||
using endpoint_type_t = typename endpoint_type<I>::type;
|
||||
|
||||
}
|
||||
|
||||
#endif // __ODRIVE_ENDPOINTS_HPP
|
||||
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* This file is a very small part of the GCC STL because AVR-GCC ships
|
||||
* without the STL.
|
||||
*/
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
/**
|
||||
* @defgroup metaprogramming Metaprogramming
|
||||
* @ingroup utilities
|
||||
*
|
||||
* Template utilities for compile-time introspection and modification,
|
||||
* including type classification traits, type property inspection traits
|
||||
* and type transformation traits.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/// integral_constant
|
||||
template<typename _Tp, _Tp __v>
|
||||
struct integral_constant
|
||||
{
|
||||
static constexpr _Tp value = __v;
|
||||
typedef _Tp value_type;
|
||||
typedef integral_constant<_Tp, __v> type;
|
||||
constexpr operator value_type() const noexcept { return value; }
|
||||
#if __cplusplus > 201103L
|
||||
|
||||
#define __cpp_lib_integral_constant_callable 201304
|
||||
|
||||
constexpr value_type operator()() const noexcept { return value; }
|
||||
#endif
|
||||
};
|
||||
|
||||
template<typename _Tp, _Tp __v>
|
||||
constexpr _Tp integral_constant<_Tp, __v>::value;
|
||||
|
||||
/// The type used as a compile-time boolean with true value.
|
||||
typedef integral_constant<bool, true> true_type;
|
||||
|
||||
/// The type used as a compile-time boolean with false value.
|
||||
typedef integral_constant<bool, false> false_type;
|
||||
|
||||
template<bool __v>
|
||||
using __bool_constant = integral_constant<bool, __v>;
|
||||
|
||||
#if __cplusplus > 201402L
|
||||
# define __cpp_lib_bool_constant 201505
|
||||
template<bool __v>
|
||||
using bool_constant = integral_constant<bool, __v>;
|
||||
#endif
|
||||
|
||||
|
||||
// Primary type categories.
|
||||
|
||||
template<typename>
|
||||
struct remove_cv;
|
||||
|
||||
template<typename>
|
||||
struct __is_void_helper
|
||||
: public false_type { };
|
||||
|
||||
template<>
|
||||
struct __is_void_helper<void>
|
||||
: public true_type { };
|
||||
|
||||
/// is_void
|
||||
template<typename _Tp>
|
||||
struct is_void
|
||||
: public __is_void_helper<typename remove_cv<_Tp>::type>::type
|
||||
{ };
|
||||
|
||||
template<typename>
|
||||
struct __is_integral_helper
|
||||
: public false_type { };
|
||||
|
||||
template<>
|
||||
struct __is_integral_helper<bool>
|
||||
: public true_type { };
|
||||
|
||||
template<>
|
||||
struct __is_integral_helper<char>
|
||||
: public true_type { };
|
||||
|
||||
template<>
|
||||
struct __is_integral_helper<signed char>
|
||||
: public true_type { };
|
||||
|
||||
template<>
|
||||
struct __is_integral_helper<unsigned char>
|
||||
: public true_type { };
|
||||
|
||||
#ifdef _GLIBCXX_USE_WCHAR_T
|
||||
template<>
|
||||
struct __is_integral_helper<wchar_t>
|
||||
: public true_type { };
|
||||
#endif
|
||||
|
||||
template<>
|
||||
struct __is_integral_helper<char16_t>
|
||||
: public true_type { };
|
||||
|
||||
template<>
|
||||
struct __is_integral_helper<char32_t>
|
||||
: public true_type { };
|
||||
|
||||
template<>
|
||||
struct __is_integral_helper<short>
|
||||
: public true_type { };
|
||||
|
||||
template<>
|
||||
struct __is_integral_helper<unsigned short>
|
||||
: public true_type { };
|
||||
|
||||
template<>
|
||||
struct __is_integral_helper<int>
|
||||
: public true_type { };
|
||||
|
||||
template<>
|
||||
struct __is_integral_helper<unsigned int>
|
||||
: public true_type { };
|
||||
|
||||
template<>
|
||||
struct __is_integral_helper<long>
|
||||
: public true_type { };
|
||||
|
||||
template<>
|
||||
struct __is_integral_helper<unsigned long>
|
||||
: public true_type { };
|
||||
|
||||
template<>
|
||||
struct __is_integral_helper<long long>
|
||||
: public true_type { };
|
||||
|
||||
template<>
|
||||
struct __is_integral_helper<unsigned long long>
|
||||
: public true_type { };
|
||||
|
||||
// Conditionalizing on __STRICT_ANSI__ here will break any port that
|
||||
// uses one of these types for size_t.
|
||||
#if defined(__GLIBCXX_TYPE_INT_N_0)
|
||||
template<>
|
||||
struct __is_integral_helper<__GLIBCXX_TYPE_INT_N_0>
|
||||
: public true_type { };
|
||||
|
||||
template<>
|
||||
struct __is_integral_helper<unsigned __GLIBCXX_TYPE_INT_N_0>
|
||||
: public true_type { };
|
||||
#endif
|
||||
#if defined(__GLIBCXX_TYPE_INT_N_1)
|
||||
template<>
|
||||
struct __is_integral_helper<__GLIBCXX_TYPE_INT_N_1>
|
||||
: public true_type { };
|
||||
|
||||
template<>
|
||||
struct __is_integral_helper<unsigned __GLIBCXX_TYPE_INT_N_1>
|
||||
: public true_type { };
|
||||
#endif
|
||||
#if defined(__GLIBCXX_TYPE_INT_N_2)
|
||||
template<>
|
||||
struct __is_integral_helper<__GLIBCXX_TYPE_INT_N_2>
|
||||
: public true_type { };
|
||||
|
||||
template<>
|
||||
struct __is_integral_helper<unsigned __GLIBCXX_TYPE_INT_N_2>
|
||||
: public true_type { };
|
||||
#endif
|
||||
#if defined(__GLIBCXX_TYPE_INT_N_3)
|
||||
template<>
|
||||
struct __is_integral_helper<__GLIBCXX_TYPE_INT_N_3>
|
||||
: public true_type { };
|
||||
|
||||
template<>
|
||||
struct __is_integral_helper<unsigned __GLIBCXX_TYPE_INT_N_3>
|
||||
: public true_type { };
|
||||
#endif
|
||||
|
||||
/// is_integral
|
||||
template<typename _Tp>
|
||||
struct is_integral
|
||||
: public __is_integral_helper<typename remove_cv<_Tp>::type>::type
|
||||
{ };
|
||||
|
||||
template<typename>
|
||||
struct __is_floating_point_helper
|
||||
: public false_type { };
|
||||
|
||||
template<>
|
||||
struct __is_floating_point_helper<float>
|
||||
: public true_type { };
|
||||
|
||||
template<>
|
||||
struct __is_floating_point_helper<double>
|
||||
: public true_type { };
|
||||
|
||||
template<>
|
||||
struct __is_floating_point_helper<long double>
|
||||
: public true_type { };
|
||||
|
||||
#if !defined(__STRICT_ANSI__) && defined(_GLIBCXX_USE_FLOAT128)
|
||||
template<>
|
||||
struct __is_floating_point_helper<__float128>
|
||||
: public true_type { };
|
||||
#endif
|
||||
|
||||
/// is_floating_point
|
||||
template<typename _Tp>
|
||||
struct is_floating_point
|
||||
: public __is_floating_point_helper<typename remove_cv<_Tp>::type>::type
|
||||
{ };
|
||||
|
||||
|
||||
|
||||
|
||||
// Const-volatile modifications.
|
||||
|
||||
/// remove_const
|
||||
template<typename _Tp>
|
||||
struct remove_const
|
||||
{ typedef _Tp type; };
|
||||
|
||||
template<typename _Tp>
|
||||
struct remove_const<_Tp const>
|
||||
{ typedef _Tp type; };
|
||||
|
||||
/// remove_volatile
|
||||
template<typename _Tp>
|
||||
struct remove_volatile
|
||||
{ typedef _Tp type; };
|
||||
|
||||
template<typename _Tp>
|
||||
struct remove_volatile<_Tp volatile>
|
||||
{ typedef _Tp type; };
|
||||
|
||||
/// remove_cv
|
||||
template<typename _Tp>
|
||||
struct remove_cv
|
||||
{
|
||||
typedef typename
|
||||
remove_const<typename remove_volatile<_Tp>::type>::type type;
|
||||
};
|
||||
|
||||
|
||||
// Primary template.
|
||||
/// Define a member typedef @c type only if a boolean constant is true.
|
||||
template<bool, typename _Tp = void>
|
||||
struct enable_if
|
||||
{ };
|
||||
|
||||
// Partial specialization for true.
|
||||
template<typename _Tp>
|
||||
struct enable_if<true, _Tp>
|
||||
{ typedef _Tp type; };
|
||||
|
||||
|
||||
// Type relations.
|
||||
|
||||
/// is_same
|
||||
template<typename, typename>
|
||||
struct is_same
|
||||
: public false_type { };
|
||||
|
||||
template<typename _Tp>
|
||||
struct is_same<_Tp, _Tp>
|
||||
: public true_type { };
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 Oskar Weigl
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,116 @@
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "ODriveArduino.h"
|
||||
|
||||
static const int kMotorOffsetFloat = 2;
|
||||
static const int kMotorStrideFloat = 28;
|
||||
static const int kMotorOffsetInt32 = 0;
|
||||
static const int kMotorStrideInt32 = 4;
|
||||
static const int kMotorOffsetBool = 0;
|
||||
static const int kMotorStrideBool = 4;
|
||||
static const int kMotorOffsetUint16 = 0;
|
||||
static const int kMotorStrideUint16 = 2;
|
||||
|
||||
// Print with stream operator
|
||||
template<class T> inline Print& operator <<(Print &obj, T arg) { obj.print(arg); return obj; }
|
||||
template<> inline Print& operator <<(Print &obj, float arg) { obj.print(arg, 4); return obj; }
|
||||
|
||||
ODriveArduino::ODriveArduino(Stream& serial)
|
||||
: serial_(serial) {}
|
||||
|
||||
void ODriveArduino::SetPosition(int motor_number, float position) {
|
||||
SetPosition(motor_number, position, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
void ODriveArduino::SetPosition(int motor_number, float position, float velocity_feedforward) {
|
||||
SetPosition(motor_number, position, velocity_feedforward, 0.0f);
|
||||
}
|
||||
|
||||
void ODriveArduino::SetPosition(int motor_number, float position, float velocity_feedforward, float current_feedforward) {
|
||||
serial_ << "$p " << motor_number << " " << position << " " << velocity_feedforward << " " << current_feedforward << "!";
|
||||
}
|
||||
|
||||
void ODriveArduino::SetVelocity(int motor_number, float velocity) {
|
||||
SetVelocity(motor_number, velocity, 0.0f);
|
||||
}
|
||||
|
||||
void ODriveArduino::SetVelocity(int motor_number, float velocity, float current_feedforward) {
|
||||
serial_ << "$v " << motor_number << " " << velocity << " " << current_feedforward << "!";
|
||||
}
|
||||
|
||||
float ODriveArduino::getBusVoltage() {
|
||||
serial_ << "$g 0 0!";
|
||||
return readFloat();
|
||||
}
|
||||
|
||||
float ODriveArduino::GetParameter(int motor_number, ParamNamesFloat parameter) {
|
||||
int idx = kMotorOffsetFloat + kMotorStrideFloat * motor_number + parameter;
|
||||
serial_ << "$g 0 " << idx << "!";
|
||||
return readString().toFloat();
|
||||
}
|
||||
|
||||
int32_t ODriveArduino::GetParameter(int motor_number, ParamNamesInt32 parameter) {
|
||||
int idx = kMotorOffsetInt32 + kMotorStrideInt32 * motor_number + parameter;
|
||||
serial_ << "$g 1 " << idx << "!";
|
||||
return readString().toInt();
|
||||
}
|
||||
|
||||
bool ODriveArduino::GetParameter(int motor_number, ParamNamesBool parameter) {
|
||||
int idx = kMotorOffsetBool + kMotorStrideBool * motor_number + parameter;
|
||||
serial_ << "$g 2 " << idx << "!";
|
||||
return readString().toInt();
|
||||
}
|
||||
|
||||
uint16_t ODriveArduino::GetParameter(int motor_number, ParamNamesUint16 parameter) {
|
||||
int idx = kMotorOffsetUint16 + kMotorStrideUint16 * motor_number + parameter;
|
||||
serial_ << "$g 3 " << idx << "!";
|
||||
return readString().toInt();
|
||||
}
|
||||
|
||||
|
||||
void ODriveArduino::SetParameter(int motor_number, ParamNamesFloat parameter, float value) {
|
||||
int idx = kMotorOffsetFloat + kMotorStrideFloat * motor_number + parameter;
|
||||
serial_ << "$s 0 " << idx << " " << value << "!";
|
||||
}
|
||||
|
||||
void ODriveArduino::SetParameter(int motor_number, ParamNamesInt32 parameter, int32_t value) {
|
||||
int idx = kMotorOffsetInt32 + kMotorStrideInt32 * motor_number + parameter;
|
||||
serial_ << "$s 1 " << idx << " " << value << "!";
|
||||
}
|
||||
|
||||
void ODriveArduino::SetParameter(int motor_number, ParamNamesBool parameter, bool value) {
|
||||
int idx = kMotorOffsetBool + kMotorStrideBool * motor_number + parameter;
|
||||
serial_ << "$s 2 " << idx << " " << value << "!";
|
||||
}
|
||||
|
||||
void ODriveArduino::SetParameter(int motor_number, ParamNamesUint16 parameter, uint16_t value) {
|
||||
int idx = kMotorOffsetUint16 + kMotorStrideUint16 * motor_number + parameter;
|
||||
serial_ << "$s 3 " << idx << " " << value << "!";
|
||||
}
|
||||
|
||||
|
||||
float ODriveArduino::readFloat() {
|
||||
return readString().toFloat();
|
||||
}
|
||||
|
||||
int32_t ODriveArduino::readInt() {
|
||||
return readString().toInt();
|
||||
}
|
||||
|
||||
String ODriveArduino::readString() {
|
||||
String str = "";
|
||||
static const unsigned long timeout = 1000;
|
||||
unsigned long timeout_start = millis();
|
||||
for (;;) {
|
||||
while (!serial_.available()) {
|
||||
if (millis() - timeout_start >= timeout) {
|
||||
return str;
|
||||
}
|
||||
}
|
||||
char c = serial_.read();
|
||||
if (c == '\n')
|
||||
break;
|
||||
str += c;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
|
||||
#ifndef ODriveArduino_h
|
||||
#define ODriveArduino_h
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
class ODriveArduino {
|
||||
public:
|
||||
enum ParamNamesFloat {
|
||||
PARAM_FLOAT_POS_SETPOINT,
|
||||
PARAM_FLOAT_POS_GAIN,
|
||||
PARAM_FLOAT_VEL_SETPOINT,
|
||||
PARAM_FLOAT_VEL_GAIN,
|
||||
PARAM_FLOAT_VEL_INTEGRATOR_GAIN,
|
||||
PARAM_FLOAT_VEL_INTEGRATOR_CURRENT,
|
||||
PARAM_FLOAT_VEL_LIMIT,
|
||||
PARAM_FLOAT_CURRENT_SETPOINT,
|
||||
PARAM_FLOAT_CALIBRATION_CURRENT,
|
||||
PARAM_FLOAT_PHASE_INDUCTANCE,
|
||||
PARAM_FLOAT_PHASE_RESISTANCE,
|
||||
PARAM_FLOAT_CURRENT_MEAS_PHB,
|
||||
PARAM_FLOAT_CURRENT_MEAS_PHC,
|
||||
PARAM_FLOAT_DC_CALIB_PHB,
|
||||
PARAM_FLOAT_DC_CALIB_PHC,
|
||||
PARAM_FLOAT_SHUNT_CONDUCTANCE,
|
||||
PARAM_FLOAT_PHASE_CURRENT_REV_GAIN,
|
||||
PARAM_FLOAT_CURRENT_CONTROL_CURRENT_LIM,
|
||||
PARAM_FLOAT_CURRENT_CONTROL_P_GAIN,
|
||||
PARAM_FLOAT_CURRENT_CONTROL_I_GAIN,
|
||||
PARAM_FLOAT_CURRENT_CONTROL_V_CURRENT_CONTROL_INTEGRAL_D,
|
||||
PARAM_FLOAT_CURRENT_CONTROL_V_CURRENT_CONTROL_INTEGRAL_Q,
|
||||
PARAM_FLOAT_CURRENT_CONTROL_IBUS,
|
||||
PARAM_FLOAT_ENCODER_PHASE,
|
||||
PARAM_FLOAT_ENCODER_PLL_POS,
|
||||
PARAM_FLOAT_ENCODER_PLL_VEL,
|
||||
PARAM_FLOAT_ENCODER_PLL_KP,
|
||||
PARAM_FLOAT_ENCODER_PLL_KI,
|
||||
};
|
||||
|
||||
enum ParamNamesInt32 {
|
||||
PARAM_INT_CONTROL_MODE,
|
||||
PARAM_INT_ENCODER_ENCODER_OFFSET,
|
||||
PARAM_INT_ENCODER_ENCODER_STATE,
|
||||
PARAM_INT_ERROR,
|
||||
};
|
||||
|
||||
enum ParamNamesBool{
|
||||
PARAM_BOOL_THREAD_READY,
|
||||
PARAM_BOOL_ENABLE_CONTROL,
|
||||
PARAM_BOOL_DO_CALIBRATION,
|
||||
PARAM_BOOL_CALIBRATION_OK,
|
||||
};
|
||||
|
||||
enum ParamNamesUint16{
|
||||
PARAM_UINT16_CONTROL_DEADLINE,
|
||||
PARAM_UINT16_LAST_CPU_TIME,
|
||||
};
|
||||
|
||||
ODriveArduino(Stream& serial);
|
||||
|
||||
// Get
|
||||
float getBusVoltage();
|
||||
|
||||
float GetParameter(int motor_number, ParamNamesFloat parameter);
|
||||
int32_t GetParameter(int motor_number, ParamNamesInt32 parameter);
|
||||
bool GetParameter(int motor_number, ParamNamesBool parameter);
|
||||
uint16_t GetParameter(int motor_number, ParamNamesUint16 parameter);
|
||||
|
||||
// Set
|
||||
void SetPosition(int motor_number, float position);
|
||||
void SetPosition(int motor_number, float position, float velocity_feedforward);
|
||||
void SetPosition(int motor_number, float position, float velocity_feedforward, float current_feedforward);
|
||||
void SetVelocity(int motor_number, float velocity);
|
||||
void SetVelocity(int motor_number, float velocity, float current_feedforward);
|
||||
|
||||
void SetParameter(int motor_number, ParamNamesFloat parameter, float value);
|
||||
void SetParameter(int motor_number, ParamNamesInt32 parameter, int32_t value);
|
||||
void SetParameter(int motor_number, ParamNamesBool parameter, bool value);
|
||||
void SetParameter(int motor_number, ParamNamesUint16 parameter, uint16_t value);
|
||||
private:
|
||||
float readFloat();
|
||||
int32_t readInt();
|
||||
String readString();
|
||||
|
||||
Stream& serial_;
|
||||
};
|
||||
|
||||
#endif //ODriveArduino_h
|
||||
@@ -0,0 +1,10 @@
|
||||
# ODriveArduino
|
||||
Arduino library for the ODrive
|
||||
|
||||
To install the library, first clone this repository. In the Arduino IDE select: *Sketch -> Include Library -> Add .ZIP Library...*
|
||||
|
||||
Select the enclosing folder (e.g. ODriveArduino) to add it. Restarting the Arduino IDE may be necessary to see the examples in the *File* dropdown. Check the included example *ODriveArduinoTest* for basic usage.
|
||||
|
||||
**Important Note: The Arduino library currently only supports the legacy UART protocol. This is selected in the firmware in [MotorControl/commands.h](https://github.com/madcowswe/ODrive/blob/master/Firmware/MotorControl/commands.h), with UART_PROTOCOL_LEGACY**
|
||||
|
||||
For most applications, this protocol is sufficient. Future versions of the Arduino library will be upgraded to support the current binary protocol.
|
||||
@@ -0,0 +1,75 @@
|
||||
|
||||
#include <SoftwareSerial.h>
|
||||
#include <ODriveArduino.h>
|
||||
|
||||
// Printing with stream operator
|
||||
template<class T> inline Print& operator <<(Print &obj, T arg) { obj.print(arg); return obj; }
|
||||
template<> inline Print& operator <<(Print &obj, float arg) { obj.print(arg, 4); return obj; }
|
||||
|
||||
// Serial to the ODrive
|
||||
SoftwareSerial odrive_serial(8, 9); //RX (ODrive TX), TX (ODrive RX)
|
||||
|
||||
// ODrive object
|
||||
ODriveArduino odrive(odrive_serial);
|
||||
|
||||
void setup() {
|
||||
// ODrive uses 115200 baud
|
||||
odrive_serial.begin(115200);
|
||||
|
||||
// Serial to PC
|
||||
Serial.begin(115200);
|
||||
while (!Serial) ; // wait for Arduino Serial Monitor to open
|
||||
|
||||
Serial.println("ODriveArduino alpha.");
|
||||
Serial.println("Setting parameters...");
|
||||
|
||||
// In this example we set the same parameters to both motors.
|
||||
// You can of course set them different if you want.
|
||||
for (int motor = 0; motor < 2; ++motor) {
|
||||
odrive.SetParameter(motor, odrive.PARAM_FLOAT_CURRENT_CONTROL_CURRENT_LIM, 10.0f); // [A]
|
||||
odrive.SetParameter(motor, odrive.PARAM_FLOAT_VEL_LIMIT, 20000.0f); // [counts/s]
|
||||
odrive.SetParameter(motor, odrive.PARAM_FLOAT_POS_GAIN, 20.0f); // [(counts/s) / counts]
|
||||
odrive.SetParameter(motor, odrive.PARAM_FLOAT_VEL_GAIN, 15.0f/10000.0f); // [A/(counts/s)]
|
||||
odrive.SetParameter(motor, odrive.PARAM_FLOAT_VEL_INTEGRATOR_GAIN, 0.0f/10000.0f); // [A/(counts/s * s)]
|
||||
}
|
||||
|
||||
Serial.println("Ready!");
|
||||
Serial.println("Send the character 's' to exectue test move");
|
||||
Serial.println("Send the character 'b' to read bus voltage");
|
||||
Serial.println("Send the character 'p' to read motor positions in a 10s loop");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
if (Serial.available()) {
|
||||
char c = Serial.read();
|
||||
|
||||
// Sinusoidal test move
|
||||
if (c == 's') {
|
||||
for (float ph = 0.0f; ph < 6.28318530718f; ph += 0.01f) {
|
||||
float pos_m0 = 20000.0f * cos(ph);
|
||||
float pos_m1 = 20000.0f * sin(ph);
|
||||
odrive.SetPosition(0, pos_m0);
|
||||
odrive.SetPosition(1, pos_m1);
|
||||
delay(5);
|
||||
}
|
||||
}
|
||||
|
||||
// Read bus voltage
|
||||
if (c == 'b') {
|
||||
Serial << "Vbus voltage: " << odrive.getBusVoltage() << '\n';
|
||||
}
|
||||
|
||||
// print motor positions in a 10s loop
|
||||
if (c == 'p') {
|
||||
static const unsigned long duration = 10000;
|
||||
unsigned long start = millis();
|
||||
while(millis() - start < duration) {
|
||||
for (int motor = 0; motor < 2; ++motor) {
|
||||
Serial << odrive.GetParameter(motor, odrive.PARAM_FLOAT_ENCODER_PLL_POS) << '\t';
|
||||
}
|
||||
Serial << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user