#ifndef __AXIS_HPP #define __AXIS_HPP #ifndef __ODRIVE_MAIN_HPP #error "This file should not be included directly. Include odrive_main.hpp instead." #endif // Warning: Do not reorder these enum values. // The state machine uses ">" comparision on them. enum AxisState_t { AXIS_STATE_UNDEFINED, // void run_control_loop(const T& update_handler) { while (requested_state_ == AXIS_STATE_UNDEFINED) { if (motor_.error_ != Motor::ERROR_NO_ERROR) { error_ = ERROR_MOTOR_FAILED; break; } if ((current_state_ != AXIS_STATE_IDLE) && missed_control_deadline_) { error_ = ERROR_CONTROL_LOOP_TIMEOUT; break; } if (!do_checks()) // error set during function call break; if (!update_handler()) // error set during function call break; // Check we meet deadlines after queueing ++loop_counter_; // Wait until the current measurement interrupt fires if (!wait_for_current_meas()) { // error set by function call motor_.disarm(); // maybe the interrupt handler is dead, let's be safe and float all phases break; } } } bool run_sensorless_spin_up(); bool run_sensorless_control_loop(); bool run_closed_loop_control_loop(); bool run_idle_loop(); void run_state_machine_loop(); const AxisHardwareConfig_t& hw_config_; AxisConfig_t& config_; Encoder& encoder_; SensorlessEstimator& sensorless_estimator_; Controller& controller_; Motor& motor_; osThreadId thread_id_; volatile bool thread_id_valid_ = false; // variables exposed on protocol Error_t error_ = ERROR_NO_ERROR; bool missed_control_deadline_ = true; // this flag is raised by the interrupt handler // whenever there's no active control loop that // sets the timings. The flag must be explicitly // cleared by a call to motors.arm(). bool enable_step_dir_ = false; // auto enabled after calibration, based on config.enable_step_dir AxisState_t requested_state_ = AXIS_STATE_STARTUP_SEQUENCE; AxisState_t task_chain_[10] = { AXIS_STATE_UNDEFINED }; AxisState_t& current_state_ = task_chain_[0]; uint32_t loop_counter_ = 0; // Communication protocol definitions auto make_protocol_definitions() { return make_protocol_member_list( make_protocol_ro_property("error", &error_), make_protocol_ro_property("missed_control_deadline", &missed_control_deadline_), make_protocol_property("enable_step_dir", &enable_step_dir_), make_protocol_ro_property("current_state", ¤t_state_), make_protocol_property("requested_state", &requested_state_), make_protocol_ro_property("loop_counter", &loop_counter_), make_protocol_object("config", make_protocol_property("startup_motor_calibration", &config_.startup_motor_calibration), make_protocol_property("startup_encoder_calibration", &config_.startup_encoder_calibration), make_protocol_property("startup_closed_loop_control", &config_.startup_closed_loop_control), make_protocol_property("startup_sensorless_control", &config_.startup_sensorless_control), make_protocol_property("enable_step_dir", &config_.enable_step_dir), make_protocol_property("counts_per_step", &config_.counts_per_step), make_protocol_property("dc_bus_brownout_trip_level", &config_.dc_bus_brownout_trip_level), make_protocol_property("ramp_up_time", &config_.ramp_up_time), make_protocol_property("ramp_up_distance", &config_.ramp_up_distance), make_protocol_property("spin_up_current", &config_.spin_up_current), make_protocol_property("spin_up_acceleration", &config_.spin_up_acceleration), make_protocol_property("spin_up_target_vel", &config_.spin_up_target_vel) ), make_protocol_object("motor", motor_.make_protocol_definitions()), make_protocol_object("controller", controller_.make_protocol_definitions()), make_protocol_object("encoder", encoder_.make_protocol_definitions()) ); } }; #endif /* __AXIS_HPP */