Files
ODrive/Firmware/MotorControl/axis.hpp
T

199 lines
6.4 KiB
C++

#ifndef __AXIS_HPP
#define __AXIS_HPP
class Axis;
#include "encoder.hpp"
#include "acim_estimator.hpp"
#include "sensorless_estimator.hpp"
#include "controller.hpp"
#include "open_loop_controller.hpp"
#include "trapTraj.hpp"
#include "endstop.hpp"
#include "mechanical_brake.hpp"
#include "low_level.h"
#include "utils.hpp"
#include "task_timer.hpp"
#include <array>
class Axis : public ODriveIntf::AxisIntf {
public:
struct LockinConfig_t {
float current = 10.0f; // [A]
float ramp_time = 0.4f; // [s]
float ramp_distance = 1 * M_PI; // [rad]
float accel = 20.0f; // [rad/s^2]
float vel = 40.0f; // [rad/s]
float finish_distance = 100.0f; // [rad]
bool finish_on_vel = false;
bool finish_on_distance = false;
bool finish_on_enc_idx = false;
};
struct TaskTimes {
TaskTimer thermistor_update;
TaskTimer encoder_update;
TaskTimer sensorless_estimator_update;
TaskTimer endstop_update;
TaskTimer can_heartbeat;
TaskTimer controller_update;
TaskTimer open_loop_controller_update;
TaskTimer acim_estimator_update;
TaskTimer motor_update;
TaskTimer current_controller_update;
TaskTimer dc_calib;
TaskTimer current_sense;
TaskTimer pwm_update;
};
static LockinConfig_t default_calibration();
static LockinConfig_t default_sensorless();
static LockinConfig_t default_lockin();
struct CANConfig_t {
uint32_t node_id = 0;
bool is_extended = false;
uint32_t heartbeat_rate_ms = 100;
uint32_t encoder_rate_ms = 10;
};
struct Config_t {
bool startup_motor_calibration = false; //<! run motor calibration at startup, skip otherwise
bool startup_encoder_index_search = false; //<! run encoder index search after startup, skip otherwise
// this only has an effect if encoder.config.use_index is also true
bool startup_encoder_offset_calibration = false; //<! run encoder offset calibration after startup, skip otherwise
bool startup_closed_loop_control = false; //<! enable closed loop control after calibration/startup
bool startup_homing = false; //<! enable homing after calibration/startup
bool enable_step_dir = false; //<! enable step/dir input after calibration
// For M0 this has no effect if enable_uart is true
bool step_dir_always_on = false; //<! Keep step/dir enabled while the motor is disabled.
//<! This is ignored if enable_step_dir is false.
//<! This setting only takes effect on a state transition
//<! into idle or out of closed loop control.
bool enable_sensorless_mode = false;
float watchdog_timeout = 0.0f; // [s]
bool enable_watchdog = false;
// Defaults loaded from hw_config in load_configuration in main.cpp
uint16_t step_gpio_pin = 0;
uint16_t dir_gpio_pin = 0;
LockinConfig_t calibration_lockin = default_calibration();
LockinConfig_t sensorless_ramp = default_sensorless();
LockinConfig_t general_lockin;
CANConfig_t can;
// custom setters
Axis* parent = nullptr;
void set_step_gpio_pin(uint16_t value) { step_gpio_pin = value; parent->decode_step_dir_pins(); }
void set_dir_gpio_pin(uint16_t value) { dir_gpio_pin = value; parent->decode_step_dir_pins(); }
};
struct Homing_t {
bool is_homed = false;
};
struct CAN_t {
uint32_t last_heartbeat = 0;
uint32_t last_encoder = 0;
};
Axis(int axis_num,
uint16_t default_step_gpio_pin,
uint16_t default_dir_gpio_pin,
osPriority thread_priority,
Encoder& encoder,
SensorlessEstimator& sensorless_estimator,
Controller& controller,
Motor& motor,
TrapezoidalTrajectory& trap,
Endstop& min_endstop,
Endstop& max_endstop,
MechanicalBrake& mechanical_brake);
bool apply_config();
void clear_config();
void start_thread();
bool wait_for_control_iteration();
void step_cb();
void set_step_dir_active(bool enable);
void decode_step_dir_pins();
bool do_checks(uint32_t timestamp);
void watchdog_feed();
bool watchdog_check();
// True if there are no errors
bool inline check_for_errors() {
return error_ == ERROR_NONE;
}
bool start_closed_loop_control();
bool stop_closed_loop_control();
bool run_lockin_spin(const LockinConfig_t &lockin_config, bool remain_armed,
std::function<bool(bool)> loop_cb = {} );
bool run_closed_loop_control_loop();
bool run_homing();
bool run_idle_loop();
constexpr uint32_t get_watchdog_reset() {
return static_cast<uint32_t>(std::clamp<float>(config_.watchdog_timeout, 0, UINT32_MAX / (current_meas_hz + 1)) * current_meas_hz);
}
void run_state_machine_loop();
// hardware config
int axis_num_;
uint16_t default_step_gpio_pin_;
uint16_t default_dir_gpio_pin_;
osPriority thread_priority_;
Config_t config_;
Encoder& encoder_;
AcimEstimator acim_estimator_;
SensorlessEstimator& sensorless_estimator_;
Controller& controller_;
OpenLoopController open_loop_controller_;
Motor& motor_;
TrapezoidalTrajectory& trap_traj_;
Endstop& min_endstop_;
Endstop& max_endstop_;
MechanicalBrake& mechanical_brake_;
TaskTimes task_times_;
osThreadId thread_id_ = 0;
const uint32_t stack_size_ = 2048; // Bytes
volatile bool thread_id_valid_ = false;
// variables exposed on protocol
Error error_ = ERROR_NONE;
bool step_dir_active_ = false; // auto enabled after calibration, based on config.enable_step_dir
int64_t steps_ = 0; // Steps counted at interface
uint32_t last_drv_fault_ = 0;
// updated from config in constructor, and on protocol hook
Stm32Gpio step_gpio_;
Stm32Gpio dir_gpio_;
AxisState requested_state_ = AXIS_STATE_STARTUP_SEQUENCE;
std::array<AxisState, 10> task_chain_ = { AXIS_STATE_UNDEFINED };
AxisState& current_state_ = task_chain_.front();
Homing_t homing_;
CAN_t can_;
// watchdog
uint32_t watchdog_current_value_= 0;
};
#endif /* __AXIS_HPP */