diff --git a/Firmware/MotorControl/axis.cpp b/Firmware/MotorControl/axis.cpp index 172f3dc4..d501c806 100644 --- a/Firmware/MotorControl/axis.cpp +++ b/Firmware/MotorControl/axis.cpp @@ -315,7 +315,7 @@ bool Axis::run_closed_loop_control_loop() { if (!controller_.update(&torque_setpoint)) return error_ |= ERROR_CONTROLLER_FAILED, false; - float phase_vel = 2 * M_PI * encoder_.vel_estimate_ / (float)encoder_.config_.cpr * motor_.config_.pole_pairs; + float phase_vel = encoder_.vel_est_rad_ * motor_.config_.pole_pairs; if (!motor_.update(torque_setpoint, encoder_.phase_, phase_vel)) return false; // set_error should update axis.error_ @@ -364,7 +364,7 @@ bool Axis::run_homing() { if (!controller_.update(&torque_setpoint)) return error_ |= ERROR_CONTROLLER_FAILED, false; - float phase_vel = 2 * M_PI * encoder_.vel_estimate_ / (float)encoder_.config_.cpr * motor_.config_.pole_pairs; + float phase_vel = encoder_.vel_est_rad_ * motor_.config_.pole_pairs; if (!motor_.update(torque_setpoint, encoder_.phase_, phase_vel)) return false; // set_error should update axis.error_ @@ -393,7 +393,7 @@ bool Axis::run_homing() { if (!controller_.update(&torque_setpoint)) return error_ |= ERROR_CONTROLLER_FAILED, false; - float phase_vel = 2 * M_PI * encoder_.vel_estimate_ / (float)encoder_.config_.cpr * motor_.config_.pole_pairs; + float phase_vel = encoder_.vel_est_rad_ * motor_.config_.pole_pairs; if (!motor_.update(torque_setpoint, encoder_.phase_, phase_vel)) return false; // set_error should update axis.error_ diff --git a/Firmware/MotorControl/controller.cpp b/Firmware/MotorControl/controller.cpp index 190157ea..c8ea8f05 100644 --- a/Firmware/MotorControl/controller.cpp +++ b/Firmware/MotorControl/controller.cpp @@ -85,8 +85,8 @@ void Controller::start_anticogging_calibration() { */ bool Controller::anticogging_calibration(float pos_estimate, float vel_estimate) { float pos_err = input_pos_ - pos_estimate; - if (std::abs(pos_err) <= config_.anticogging.calib_pos_threshold && - std::abs(vel_estimate) < config_.anticogging.calib_vel_threshold) { + if (std::abs(pos_err) <= config_.anticogging.calib_pos_threshold * (2.0f * M_PI) / (float)axis_->encoder_.config_.cpr && + std::abs(vel_estimate) < config_.anticogging.calib_vel_threshold * (2.0f * M_PI) / (float)axis_->encoder_.config_.cpr) { config_.anticogging.cogging_map[std::clamp(config_.anticogging.index++, 0, 3600)] = vel_integrator_torque_; } if (config_.anticogging.index < 3600) { @@ -128,19 +128,19 @@ bool Controller::update(float* torque_setpoint_output) { ? vel_estimate_src_ : nullptr; // Calib_anticogging is only true when calibration is occurring, so we can't block anticogging_pos - float anticogging_pos = axis_->encoder_.pos_estimate_ / axis_->encoder_.getCoggingRatio(); + float anticogging_pos = axis_->encoder_.pos_est_rad_ / axis_->encoder_.getCoggingRatio(); if (config_.anticogging.calib_anticogging) { if (!axis_->encoder_.pos_estimate_valid_ || !axis_->encoder_.vel_estimate_valid_) { set_error(ERROR_INVALID_ESTIMATE); return false; } // non-blocking - anticogging_calibration(axis_->encoder_.pos_estimate_, axis_->encoder_.vel_estimate_); + anticogging_calibration(axis_->encoder_.pos_est_rad_, axis_->encoder_.vel_est_rad_); } // TODO also enable circular deltas for 2nd order filter, etc. if (pos_wrap_src_) { - float cpr = *pos_wrap_src_; + float cpr = *pos_wrap_src_ * 2.0f * M_PI / ((float)axis_->encoder_.config_.cpr); // Keep pos setpoint from drifting input_pos_ = fmodf_pos(input_pos_, cpr); } @@ -153,7 +153,7 @@ bool Controller::update(float* torque_setpoint_output) { case INPUT_MODE_PASSTHROUGH: { pos_setpoint_ = input_pos_; vel_setpoint_ = input_vel_; - torque_setpoint_ = input_torque_; // + torque_setpoint_ = input_torque_; } break; case INPUT_MODE_VEL_RAMP: { float max_step_size = std::abs(current_meas_period * config_.vel_ramp_rate); @@ -181,8 +181,8 @@ bool Controller::update(float* torque_setpoint_output) { } break; case INPUT_MODE_MIRROR: { if (config_.axis_to_mirror < AXIS_COUNT) { - pos_setpoint_ = axes[config_.axis_to_mirror]->encoder_.pos_estimate_ * config_.mirror_ratio; - vel_setpoint_ = axes[config_.axis_to_mirror]->encoder_.vel_estimate_ * config_.mirror_ratio; + pos_setpoint_ = axes[config_.axis_to_mirror]->encoder_.pos_est_rad_ * config_.mirror_ratio; + vel_setpoint_ = axes[config_.axis_to_mirror]->encoder_.vel_est_rad_ * config_.mirror_ratio; } else { set_error(ERROR_INVALID_MIRROR_AXIS); return false; @@ -235,7 +235,7 @@ bool Controller::update(float* torque_setpoint_output) { } if (pos_wrap_src_) { - float cpr = *pos_wrap_src_; + float cpr = *pos_wrap_src_ * 2.0f * M_PI / ((float)axis_->encoder_.config_.cpr); // Keep pos setpoint from drifting pos_setpoint_ = fmodf_pos(pos_setpoint_, cpr); // Circular delta diff --git a/Firmware/MotorControl/controller.hpp b/Firmware/MotorControl/controller.hpp index c8360643..ee85ba76 100644 --- a/Firmware/MotorControl/controller.hpp +++ b/Firmware/MotorControl/controller.hpp @@ -45,6 +45,8 @@ public: uint8_t axis_to_mirror = -1; float mirror_ratio = 1.0f; uint8_t load_encoder_axis = -1; // default depends on Axis number and is set in load_configuration() + float input_pos_multiplier = 1.0f; // if input_pos is set by user, it is multiplied by this + float input_vel_multiplier = 1.0f; // if input_vel is set by user, it is multiplied by this // custom setters Controller* parent; @@ -99,7 +101,12 @@ public: bool anticogging_valid_ = false; // custom setters - void set_input_pos(float value) { input_pos_ = value; input_pos_updated(); } + void set_input_pos(float value) { input_pos_ = value * config_.input_pos_multiplier; input_pos_updated(); } + void set_input_vel(float value) { input_vel_ = value * config_.input_vel_multiplier;} + + // custom getters + float get_input_pos(void) { return input_pos_ / (config_.input_pos_multiplier == 0.0f ? 1.0f : config_.input_pos_multiplier);} + float get_input_vel(void) { return input_vel_ / (config_.input_vel_multiplier == 0.0f ? 1.0f : config_.input_vel_multiplier);} }; #endif // __CONTROLLER_HPP diff --git a/Firmware/MotorControl/encoder.cpp b/Firmware/MotorControl/encoder.cpp index 569b438b..ad9c02e5 100644 --- a/Firmware/MotorControl/encoder.cpp +++ b/Firmware/MotorControl/encoder.cpp @@ -522,7 +522,7 @@ bool Encoder::update() { snap_to_zero_vel = true; } - //new vars in radians + //expose pos/vel estimates in radians for Controller pos_est_rad_ = pos_estimate_ * 2.0f * M_PI / (float)config_.cpr; vel_est_rad_ = vel_estimate_ * 2.0f * M_PI / (float)config_.cpr; pos_cpr_rad_ = pos_cpr_ * 2.0f * M_PI / (float)config_.cpr; diff --git a/Firmware/MotorControl/encoder.hpp b/Firmware/MotorControl/encoder.hpp index 300157dc..3fe8b3a2 100644 --- a/Firmware/MotorControl/encoder.hpp +++ b/Firmware/MotorControl/encoder.hpp @@ -74,7 +74,7 @@ public: int32_t shadow_count_ = 0; int32_t count_in_cpr_ = 0; float interpolation_ = 0.0f; - float phase_ = 0.0f; // [count] + float phase_ = 0.0f; // [count] float pos_estimate_ = 0.0f; // [count] float pos_cpr_ = 0.0f; // [count] float vel_estimate_ = 0.0f; // [count/s] @@ -84,9 +84,9 @@ public: int32_t pos_abs_ = 0; float spi_error_rate_ = 0.0f; - float pos_est_rad_ = 0.0f; - float vel_est_rad_ = 0.0f; - float pos_cpr_rad_ = 0.0f; + float pos_est_rad_ = 0.0f; // [rad] + float vel_est_rad_ = 0.0f; // [rad] + float pos_cpr_rad_ = 0.0f; // [rad] bool pos_estimate_valid_ = false; bool vel_estimate_valid_ = false; @@ -111,7 +111,7 @@ public: uint32_t abs_spi_cr2; constexpr float getCoggingRatio(){ - return config_.cpr / 3600.0f; + return 2.0f * M_PI / 3600.0f; } }; diff --git a/Firmware/communication/ascii_protocol.cpp b/Firmware/communication/ascii_protocol.cpp index 6046214f..96e03c1b 100644 --- a/Firmware/communication/ascii_protocol.cpp +++ b/Firmware/communication/ascii_protocol.cpp @@ -189,8 +189,8 @@ void ASCII_protocol_process_line(const uint8_t* buffer, size_t len, StreamSink& respond(response_channel, use_checksum, "invalid motor %u", motor_number); } else { respond(response_channel, use_checksum, "%f %f", - (double)axes[motor_number]->encoder_.pos_estimate_, - (double)axes[motor_number]->encoder_.vel_estimate_); + (double)axes[motor_number]->encoder_.pos_est_rad_, + (double)axes[motor_number]->encoder_.vel_est_rad_); } } else if (cmd[0] == 'h') { // Help diff --git a/Firmware/communication/can_simple.cpp b/Firmware/communication/can_simple.cpp index 18d39838..5679c73d 100644 --- a/Firmware/communication/can_simple.cpp +++ b/Firmware/communication/can_simple.cpp @@ -206,16 +206,16 @@ void CANSimple::get_encoder_estimates_callback(Axis* axis, can_Message_t& msg) { // uint32_t floatBytes = *(reinterpret_cast(&(axis->encoder_.pos_estimate_))); uint32_t floatBytes; - static_assert(sizeof axis->encoder_.pos_estimate_ == sizeof floatBytes); - std::memcpy(&floatBytes, &axis->encoder_.pos_estimate_, sizeof floatBytes); + static_assert(sizeof axis->encoder_.pos_est_rad_ == sizeof floatBytes); + std::memcpy(&floatBytes, &axis->encoder_.pos_est_rad_, sizeof floatBytes); txmsg.buf[0] = floatBytes; txmsg.buf[1] = floatBytes >> 8; txmsg.buf[2] = floatBytes >> 16; txmsg.buf[3] = floatBytes >> 24; - static_assert(sizeof floatBytes == sizeof axis->encoder_.vel_estimate_); - std::memcpy(&floatBytes, &axis->encoder_.vel_estimate_, sizeof floatBytes); + static_assert(sizeof floatBytes == sizeof axis->encoder_.vel_est_rad_); + std::memcpy(&floatBytes, &axis->encoder_.vel_est_rad_, sizeof floatBytes); txmsg.buf[4] = floatBytes; txmsg.buf[5] = floatBytes >> 8; txmsg.buf[6] = floatBytes >> 16; diff --git a/Firmware/odrive-interface.yaml b/Firmware/odrive-interface.yaml index b738e0df..f8b2fbfc 100644 --- a/Firmware/odrive-interface.yaml +++ b/Firmware/odrive-interface.yaml @@ -593,8 +593,8 @@ interfaces: InvalidMirrorAxis: InvalidLoadEncoder: InvalidEstimate: - input_pos: {type: float32, c_setter: set_input_pos} - input_vel: float32 + input_pos: {type: float32, c_setter: set_input_pos, c_getter: get_input_pos()} + input_vel: {type: float32, c_setter: set_input_vel, c_getter: get_input_vel()} input_torque: float32 pos_setpoint: readonly float32 vel_setpoint: readonly float32 @@ -660,6 +660,8 @@ interfaces: calib_vel_threshold: float32 cogging_ratio: readonly float32 anticogging_enabled: bool + input_pos_multiplier: float32 + input_vel_multiplier: float32 functions: move_incremental: doc: Moves the axes' goal point by a specified increment. @@ -712,9 +714,12 @@ interfaces: interpolation: readonly float32 phase: readonly float32 pos_estimate: readonly float32 + pos_est_rad: readonly float32 pos_cpr: readonly float32 + pos_cpr_rad: readonly float32 hall_state: readonly uint8 vel_estimate: readonly float32 + vel_est_rad: readonly float32 calib_scan_response: readonly float32 pos_abs: int32 spi_error_rate: readonly float32 diff --git a/tools/odrive/shell.py b/tools/odrive/shell.py index 1f83aa9c..eb4395ff 100644 --- a/tools/odrive/shell.py +++ b/tools/odrive/shell.py @@ -33,7 +33,7 @@ def print_help(args, have_devices): print('') print('For example: "odrv0.motor0.encoder.pos_estimate"') print('will print the current encoder position on motor 0') - print('and "odrv0.motor0.pos_setpoint = 10000"') + print('and "odrv0.motor0.input_pos = 10000"') print('will send motor0 to 10000') print('') diff --git a/tools/odrivetool b/tools/odrivetool index 5c3af5b7..6011de93 100755 --- a/tools/odrivetool +++ b/tools/odrivetool @@ -8,6 +8,7 @@ import sys import os import argparse import time +import math sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname( os.path.realpath(__file__))), @@ -151,8 +152,8 @@ try: # If you want to plot different values, change them here. # You can plot any number of values concurrently. cancellation_token = start_liveplotter(lambda: [ - my_odrive.axis0.encoder.pos_estimate, - my_odrive.axis1.encoder.pos_estimate, + my_odrive.axis0.encoder.pos_est_rad, + my_odrive.axis1.encoder.pos_est_rad, ]) print("Showing plot. Press Ctrl+C to exit.")