Files
MotorDriver.Research/Makerbase_ODrive/ODrive-fw-v0.5.1/Firmware/MotorControl/odrive_main.h
T
2025-05-13 01:34:53 +03:00

298 lines
12 KiB
C++

#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 */