*
This commit is contained in:
@@ -0,0 +1,297 @@
|
||||
#ifndef __ODRIVE_MAIN_H
|
||||
#define __ODRIVE_MAIN_H
|
||||
|
||||
// Note on central include scheme by Samuel:
|
||||
// there are circular dependencies between some of the header files,
|
||||
// e.g. the Motor header needs a forward declaration of Axis and vice versa
|
||||
// so I figured I'd make one main header that takes care of
|
||||
// the forward declarations and right ordering
|
||||
// btw this pattern is not so uncommon, for instance IIRC the stdlib uses it too
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <fibre/protocol.hpp>
|
||||
#include <communication/interface_usb.h>
|
||||
#include <communication/interface_i2c.h>
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// STM specific includes
|
||||
#include <stm32f4xx_hal.h> // Sets up the correct chip specifc defines required by arm_math
|
||||
#include <can.h>
|
||||
#include <i2c.h>
|
||||
#define ARM_MATH_CM4 // TODO: might change in future board versions
|
||||
#include <arm_math.h>
|
||||
|
||||
// OS includes
|
||||
#include <cmsis_os.h>
|
||||
|
||||
// Hardware configuration
|
||||
#if HW_VERSION_MAJOR == 3
|
||||
#include "board_config_v3.h"
|
||||
#else
|
||||
#error "unknown board version"
|
||||
#endif
|
||||
|
||||
//default timeout waiting for phase measurement signals
|
||||
#define PH_CURRENT_MEAS_TIMEOUT 2 // [ms]
|
||||
|
||||
// Period in [s]
|
||||
static const float current_meas_period = CURRENT_MEAS_PERIOD;
|
||||
|
||||
// Frequency in [Hz]
|
||||
static const int current_meas_hz = CURRENT_MEAS_HZ;
|
||||
|
||||
// extern const float elec_rad_per_enc;
|
||||
extern uint32_t _reboot_cookie;
|
||||
|
||||
extern uint64_t serial_number;
|
||||
extern char serial_number_str[13];
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
bool fully_booted;
|
||||
uint32_t uptime; // [ms]
|
||||
uint32_t min_heap_space; // FreeRTOS heap [Bytes]
|
||||
uint32_t min_stack_space_axis0; // minimum remaining space since startup [Bytes]
|
||||
uint32_t min_stack_space_axis1;
|
||||
uint32_t min_stack_space_comms;
|
||||
uint32_t min_stack_space_usb;
|
||||
uint32_t min_stack_space_uart;
|
||||
uint32_t min_stack_space_usb_irq;
|
||||
uint32_t min_stack_space_startup;
|
||||
uint32_t min_stack_space_can;
|
||||
|
||||
uint32_t stack_usage_axis0;
|
||||
uint32_t stack_usage_axis1;
|
||||
uint32_t stack_usage_comms;
|
||||
uint32_t stack_usage_usb;
|
||||
uint32_t stack_usage_uart;
|
||||
uint32_t stack_usage_usb_irq;
|
||||
uint32_t stack_usage_startup;
|
||||
uint32_t stack_usage_can;
|
||||
|
||||
USBStats_t& usb = usb_stats_;
|
||||
I2CStats_t& i2c = i2c_stats_;
|
||||
} SystemStats_t;
|
||||
|
||||
struct PWMMapping_t {
|
||||
endpoint_ref_t endpoint;
|
||||
float min = 0;
|
||||
float max = 0;
|
||||
};
|
||||
|
||||
// @brief general user configurable board configuration
|
||||
struct BoardConfig_t {
|
||||
bool enable_uart = true;
|
||||
bool enable_i2c_instead_of_can = false;
|
||||
bool enable_ascii_protocol_on_usb = true;
|
||||
float max_regen_current = 0.0f;
|
||||
#if HW_VERSION_MAJOR == 3 && HW_VERSION_MINOR >= 5 && HW_VERSION_VOLTAGE >= 48
|
||||
float brake_resistance = 2.0f; // [ohm]
|
||||
#else
|
||||
float brake_resistance = 0.47f; // [ohm]
|
||||
#endif
|
||||
float dc_bus_undervoltage_trip_level = 8.0f; //<! [V] minimum voltage below which the motor stops operating
|
||||
float dc_bus_overvoltage_trip_level = 1.07f * HW_VERSION_VOLTAGE; //<! [V] maximum voltage above which the motor stops operating.
|
||||
//<! This protects against cases in which the power supply fails to dissipate
|
||||
//<! the brake power if the brake resistor is disabled.
|
||||
//<! The default is 26V for the 24V board version and 52V for the 48V board version.
|
||||
|
||||
/**
|
||||
* If enabled, if the measured DC voltage exceeds `dc_bus_overvoltage_ramp_start`,
|
||||
* the ODrive will sink more power than usual into the the brake resistor
|
||||
* in an attempt to bring the voltage down again.
|
||||
*
|
||||
* The brake duty cycle is increased by the following amount:
|
||||
* vbus_voltage == dc_bus_overvoltage_ramp_start => brake_duty_cycle += 0%
|
||||
* vbus_voltage == dc_bus_overvoltage_ramp_end => brake_duty_cycle += 100%
|
||||
*
|
||||
* Remarks:
|
||||
* - This feature is active even when all motors are disarmed.
|
||||
* - This feature is disabled if `brake_resistance` is non-positive.
|
||||
*/
|
||||
bool enable_dc_bus_overvoltage_ramp = false;
|
||||
float dc_bus_overvoltage_ramp_start = 1.07f * HW_VERSION_VOLTAGE; //!< See `enable_dc_bus_overvoltage_ramp`.
|
||||
//!< Do not set this lower than your usual vbus_voltage,
|
||||
//!< unless you like fried brake resistors.
|
||||
float dc_bus_overvoltage_ramp_end = 1.07f * HW_VERSION_VOLTAGE; //!< See `enable_dc_bus_overvoltage_ramp`.
|
||||
//!< Must be larger than `dc_bus_overvoltage_ramp_start`,
|
||||
//!< otherwise the ramp feature is disabled.
|
||||
|
||||
float dc_max_positive_current = INFINITY; // Max current [A] the power supply can source
|
||||
float dc_max_negative_current = -0.000001f; // Max current [A] the power supply can sink. You most likely want a non-positive value here. Set to -INFINITY to disable.
|
||||
PWMMapping_t pwm_mappings[GPIO_COUNT];
|
||||
PWMMapping_t analog_mappings[GPIO_COUNT];
|
||||
|
||||
/**
|
||||
* Defines the baudrate used on the UART interface.
|
||||
* Some baudrates will have a small timing error due to hardware limitations.
|
||||
*
|
||||
* Here's an (incomplete) list of baudrates for ODrive v3.x:
|
||||
*
|
||||
* Configured | Actual | Error [%]
|
||||
* -------------|---------------|-----------
|
||||
* 1.2 KBps | 1.2 KBps | 0
|
||||
* 2.4 KBps | 2.4 KBps | 0
|
||||
* 9.6 KBps | 9.6 KBps | 0
|
||||
* 19.2 KBps | 19.195 KBps | 0.02
|
||||
* 38.4 KBps | 38.391 KBps | 0.02
|
||||
* 57.6 KBps | 57.613 KBps | 0.02
|
||||
* 115.2 KBps | 115.068 KBps | 0.11
|
||||
* 230.4 KBps | 230.769 KBps | 0.16
|
||||
* 460.8 KBps | 461.538 KBps | 0.16
|
||||
* 921.6 KBps | 913.043 KBps | 0.93
|
||||
* 1.792 MBps | 1.826 MBps | 1.9
|
||||
* 1.8432 MBps | 1.826 MBps | 0.93
|
||||
*
|
||||
* For more information refer to Section 30.3.4 and Table 142 (the column with f_PCLK = 42 MHz) in the STM datasheet:
|
||||
* https://www.st.com/content/ccc/resource/technical/document/reference_manual/3d/6d/5a/66/b4/99/40/d4/DM00031020.pdf/files/DM00031020.pdf/jcr:content/translations/en.DM00031020.pdf
|
||||
*/
|
||||
uint32_t uart_baudrate = 115200;
|
||||
};
|
||||
|
||||
// Forward Declarations
|
||||
class Axis;
|
||||
class Motor;
|
||||
class ODriveCAN;
|
||||
|
||||
constexpr size_t AXIS_COUNT = 2;
|
||||
extern std::array<Axis*, AXIS_COUNT> axes;
|
||||
extern ODriveCAN *odCAN;
|
||||
|
||||
// if you use the oscilloscope feature you can bump up this value
|
||||
#define OSCILLOSCOPE_SIZE 4096
|
||||
extern float oscilloscope[OSCILLOSCOPE_SIZE];
|
||||
extern size_t oscilloscope_pos;
|
||||
|
||||
// TODO: move
|
||||
// this is technically not thread-safe but practically it might be
|
||||
#define DEFINE_ENUM_FLAG_OPERATORS(ENUMTYPE) \
|
||||
inline ENUMTYPE operator | (ENUMTYPE a, ENUMTYPE b) { return static_cast<ENUMTYPE>(static_cast<std::underlying_type_t<ENUMTYPE>>(a) | static_cast<std::underlying_type_t<ENUMTYPE>>(b)); } \
|
||||
inline ENUMTYPE operator & (ENUMTYPE a, ENUMTYPE b) { return static_cast<ENUMTYPE>(static_cast<std::underlying_type_t<ENUMTYPE>>(a) & static_cast<std::underlying_type_t<ENUMTYPE>>(b)); } \
|
||||
inline ENUMTYPE operator ^ (ENUMTYPE a, ENUMTYPE b) { return static_cast<ENUMTYPE>(static_cast<std::underlying_type_t<ENUMTYPE>>(a) ^ static_cast<std::underlying_type_t<ENUMTYPE>>(b)); } \
|
||||
inline ENUMTYPE &operator |= (ENUMTYPE &a, ENUMTYPE b) { return reinterpret_cast<ENUMTYPE&>(reinterpret_cast<std::underlying_type_t<ENUMTYPE>&>(a) |= static_cast<std::underlying_type_t<ENUMTYPE>>(b)); } \
|
||||
inline ENUMTYPE &operator &= (ENUMTYPE &a, ENUMTYPE b) { return reinterpret_cast<ENUMTYPE&>(reinterpret_cast<std::underlying_type_t<ENUMTYPE>&>(a) &= static_cast<std::underlying_type_t<ENUMTYPE>>(b)); } \
|
||||
inline ENUMTYPE &operator ^= (ENUMTYPE &a, ENUMTYPE b) { return reinterpret_cast<ENUMTYPE&>(reinterpret_cast<std::underlying_type_t<ENUMTYPE>&>(a) ^= static_cast<std::underlying_type_t<ENUMTYPE>>(b)); } \
|
||||
inline ENUMTYPE operator ~ (ENUMTYPE a) { return static_cast<ENUMTYPE>(~static_cast<std::underlying_type_t<ENUMTYPE>>(a)); }
|
||||
|
||||
|
||||
enum TimingLog_t {
|
||||
TIMING_LOG_GENERAL,
|
||||
TIMING_LOG_ADC_CB_I,
|
||||
TIMING_LOG_ADC_CB_DC,
|
||||
TIMING_LOG_MEAS_R,
|
||||
TIMING_LOG_MEAS_L,
|
||||
TIMING_LOG_ENC_CALIB,
|
||||
TIMING_LOG_IDX_SEARCH,
|
||||
TIMING_LOG_FOC_VOLTAGE,
|
||||
TIMING_LOG_FOC_CURRENT,
|
||||
TIMING_LOG_SPI_START,
|
||||
TIMING_LOG_SAMPLE_NOW,
|
||||
TIMING_LOG_SPI_END,
|
||||
TIMING_LOG_NUM_SLOTS
|
||||
};
|
||||
|
||||
|
||||
#include "autogen/interfaces.hpp"
|
||||
|
||||
// ODrive specific includes
|
||||
#include <utils.hpp>
|
||||
#include <gpio_utils.hpp>
|
||||
#include <low_level.h>
|
||||
#include <motor.hpp>
|
||||
#include <encoder.hpp>
|
||||
#include <sensorless_estimator.hpp>
|
||||
#include <controller.hpp>
|
||||
#include <current_limiter.hpp>
|
||||
#include <thermistor.hpp>
|
||||
#include <trapTraj.hpp>
|
||||
#include <endstop.hpp>
|
||||
#include <axis.hpp>
|
||||
#include <communication/communication.h>
|
||||
|
||||
// Defined in autogen/version.c based on git-derived version numbers
|
||||
extern "C" {
|
||||
extern const unsigned char fw_version_major_;
|
||||
extern const unsigned char fw_version_minor_;
|
||||
extern const unsigned char fw_version_revision_;
|
||||
extern const unsigned char fw_version_unreleased_;
|
||||
}
|
||||
|
||||
|
||||
// general system functions defined in main.cpp
|
||||
class ODrive : public ODriveIntf {
|
||||
public:
|
||||
void save_configuration() override;
|
||||
void erase_configuration() override;
|
||||
void reboot() override { NVIC_SystemReset(); }
|
||||
void enter_dfu_mode() override;
|
||||
|
||||
float get_oscilloscope_val(uint32_t index) override {
|
||||
return oscilloscope[index];
|
||||
}
|
||||
|
||||
float get_adc_voltage(uint32_t gpio) override {
|
||||
return ::get_adc_voltage(get_gpio_port_by_pin(gpio), get_gpio_pin_by_pin(gpio));
|
||||
}
|
||||
|
||||
int32_t test_function(int32_t delta) override {
|
||||
static int cnt = 0;
|
||||
return cnt += delta;
|
||||
}
|
||||
|
||||
Axis& get_axis(int num) { return *axes[num]; }
|
||||
ODriveCAN& get_can() { return *odCAN; }
|
||||
|
||||
float& vbus_voltage_ = ::vbus_voltage; // TODO: make this the actual variable
|
||||
float& ibus_ = ::ibus_; // TODO: make this the actual variable
|
||||
float ibus_report_filter_k_ = 1.0f;
|
||||
|
||||
const uint64_t& serial_number_ = ::serial_number;
|
||||
|
||||
#if HW_VERSION_MAJOR == 3
|
||||
// Determine start address of the OTP struct:
|
||||
// The OTP is organized into 16-byte blocks.
|
||||
// If the first block starts with "0xfe" we use the first block.
|
||||
// If the first block starts with "0x00" and the second block starts with "0xfe",
|
||||
// we use the second block. This gives the user the chance to screw up once.
|
||||
// If none of the above is the case, we consider the OTP invalid (otp_ptr will be NULL).
|
||||
const uint8_t* otp_ptr =
|
||||
(*(uint8_t*)FLASH_OTP_BASE == 0xfe) ? (uint8_t*)FLASH_OTP_BASE :
|
||||
(*(uint8_t*)FLASH_OTP_BASE != 0x00) ? NULL :
|
||||
(*(uint8_t*)(FLASH_OTP_BASE + 0x10) != 0xfe) ? NULL :
|
||||
(uint8_t*)(FLASH_OTP_BASE + 0x10);
|
||||
|
||||
// Read hardware version from OTP if available, otherwise fall back
|
||||
// to software defined version.
|
||||
const uint8_t hw_version_major_ = otp_ptr ? otp_ptr[3] : HW_VERSION_MAJOR;
|
||||
const uint8_t hw_version_minor_ = otp_ptr ? otp_ptr[4] : HW_VERSION_MINOR;
|
||||
const uint8_t hw_version_variant_ = otp_ptr ? otp_ptr[5] : HW_VERSION_VOLTAGE;
|
||||
#else
|
||||
#error "not implemented"
|
||||
#endif
|
||||
|
||||
// the corresponding macros are defined in the autogenerated version.h
|
||||
const uint8_t fw_version_major_ = ::fw_version_major_;
|
||||
const uint8_t fw_version_minor_ = ::fw_version_minor_;
|
||||
const uint8_t fw_version_revision_ = ::fw_version_revision_;
|
||||
const uint8_t fw_version_unreleased_ = ::fw_version_unreleased_; // 0 for official releases, 1 otherwise
|
||||
|
||||
bool& brake_resistor_armed_ = ::brake_resistor_armed; // TODO: make this the actual variable
|
||||
bool& brake_resistor_saturated_ = ::brake_resistor_saturated; // TODO: make this the actual variable
|
||||
|
||||
SystemStats_t system_stats_;
|
||||
|
||||
BoardConfig_t config_;
|
||||
bool user_config_loaded_;
|
||||
|
||||
uint32_t test_property_ = 0;
|
||||
};
|
||||
|
||||
extern ODrive odrv; // defined in main.cpp
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif /* __ODRIVE_MAIN_H */
|
||||
Reference in New Issue
Block a user