mirror of
https://github.com/odriverobotics/ODrive.git
synced 2026-08-18 17:49:49 +08:00
Made changes reflecting PR comments.
Added torque_ramp_rate to controller config. Changed INPUT_MODE_CURRENT_RAMP to INPUT_MODE_TORQUE_RAMP for controller input mode enum. Torque limits and current limits are now observed seperately. Torque limit is in the controller, current limit is in the motor object. Fixed torque -> current calculation in motor_update to handle ACIM motors.
This commit is contained in:
@@ -163,8 +163,8 @@ bool Controller::update(float* torque_setpoint_output) {
|
||||
vel_setpoint_ += step;
|
||||
torque_setpoint_ = (step / current_meas_period) * config_.inertia;
|
||||
} break;
|
||||
case INPUT_MODE_CURRENT_RAMP: {
|
||||
float max_step_size = std::abs(current_meas_period * config_.current_ramp_rate);
|
||||
case INPUT_MODE_TORQUE_RAMP: {
|
||||
float max_step_size = std::abs(current_meas_period * config_.torque_ramp_rate);
|
||||
float full_step = input_torque_ - torque_setpoint_;
|
||||
float step = std::clamp(full_step, -max_step_size, max_step_size);
|
||||
|
||||
@@ -319,11 +319,10 @@ bool Controller::update(float* torque_setpoint_output) {
|
||||
torque = limitVel(config_.vel_limit, *vel_estimate_src, vel_gain, torque);
|
||||
}
|
||||
|
||||
// Current limiting
|
||||
// TODO: Change to controller working in torque units
|
||||
// and get the torque limits from a function of the motor
|
||||
// Limit max torque to a user defined torque limit. This functions as an acceleration limit.
|
||||
// The motor object handles current limiting
|
||||
bool limited = false;
|
||||
float Tlim = axis_->motor_.effective_torque_lim();
|
||||
float Tlim = axis_->motor_.config_.torque_lim;
|
||||
if (torque > Tlim) {
|
||||
limited = true;
|
||||
torque = Tlim;
|
||||
|
||||
@@ -28,7 +28,7 @@ public:
|
||||
float vel_limit = 20000.0f; // [counts/s] Infinity to disable.
|
||||
float vel_limit_tolerance = 1.2f; // ratio to vel_lim. Infinity to disable.
|
||||
float vel_ramp_rate = 10000.0f; // [(counts/s) / s]
|
||||
float current_ramp_rate = 1.0f; // A / sec
|
||||
float torque_ramp_rate = 0.1f; // Nm / sec
|
||||
bool setpoints_in_cpr = false;
|
||||
float inertia = 0.0f; // [A/(count/s^2)]
|
||||
float input_filter_bandwidth = 2.0f; // [1/s]
|
||||
|
||||
@@ -177,19 +177,19 @@ bool Motor::do_checks() {
|
||||
return true;
|
||||
}
|
||||
|
||||
float Motor::effective_torque_lim() {
|
||||
float Motor::effective_current_lim() {
|
||||
// Configured limit
|
||||
float torque_lim = config_.torque_lim;
|
||||
float current_lim = config_.current_lim;
|
||||
// Hardware limit
|
||||
if (axis_->motor_.config_.motor_type == Motor::MOTOR_TYPE_GIMBAL) {
|
||||
torque_lim = std::min(torque_lim, 0.98f*one_by_sqrt3*vbus_voltage); //gimbal motor is voltage control, not Nm or A
|
||||
current_lim = std::min(current_lim, 0.98f*one_by_sqrt3*vbus_voltage); //gimbal motor is voltage control
|
||||
} else {
|
||||
torque_lim = std::min(torque_lim, axis_->motor_.current_control_.max_allowed_torque);
|
||||
current_lim = std::min(current_lim, axis_->motor_.current_control_.max_allowed_current);
|
||||
}
|
||||
// Thermal limit
|
||||
torque_lim = std::min(torque_lim, thermal_torque_lim_);
|
||||
current_lim = std::min(current_lim, thermal_current_lim_);
|
||||
|
||||
return torque_lim;
|
||||
return current_lim;
|
||||
}
|
||||
|
||||
void Motor::log_timing(TimingLog_t log_idx) {
|
||||
@@ -359,7 +359,7 @@ bool Motor::FOC_current(float Id_des, float Iq_des, float I_phase, float pwm_pha
|
||||
ictrl.Id_measured += ictrl.I_measured_report_filter_k * (Id - ictrl.Id_measured);
|
||||
|
||||
// Check for violation of current limit
|
||||
float I_trip = (effective_torque_lim() + config_.torque_lim_margin) / config_.torque_constant;
|
||||
float I_trip = effective_current_lim() + config_.current_lim_margin;
|
||||
if (SQ(Id) + SQ(Iq) > SQ(I_trip)) {
|
||||
set_error(ERROR_CURRENT_LIMIT_VIOLATION);
|
||||
return false;
|
||||
@@ -441,13 +441,20 @@ bool Motor::FOC_current(float Id_des, float Iq_des, float I_phase, float pwm_pha
|
||||
|
||||
|
||||
bool Motor::update(float torque_setpoint, float phase, float phase_vel) {
|
||||
float current_setpoint = torque_setpoint / config_.torque_constant;
|
||||
current_setpoint *= config_.direction;
|
||||
float current_setpoint;
|
||||
phase *= config_.direction;
|
||||
phase_vel *= config_.direction;
|
||||
|
||||
if (config_.motor_type == MOTOR_TYPE_ACIM) {
|
||||
current_setpoint = torque_setpoint / (config_.torque_constant * fmax(current_control_.acim_rotor_flux, config_.acim_gain_min_flux));
|
||||
}
|
||||
else {
|
||||
current_setpoint = torque_setpoint / config_.torque_constant;
|
||||
}
|
||||
current_setpoint *= config_.direction;
|
||||
|
||||
// TODO: 2-norm vs independent clamping (current could be sqrt(2) bigger)
|
||||
float ilim = effective_torque_lim() / config_.torque_constant;
|
||||
float ilim = effective_current_lim();
|
||||
float id = std::clamp(current_control_.Id_setpoint, -ilim, ilim);
|
||||
float iq = std::clamp(current_setpoint, -ilim, ilim);
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@ public:
|
||||
float Id_measured; // [A]
|
||||
float I_measured_report_filter_k;
|
||||
float max_allowed_current; // [A]
|
||||
float max_allowed_torque; // [Nm]
|
||||
float overcurrent_trip_level; // [A]
|
||||
float acim_rotor_flux; // [A]
|
||||
float async_phase_vel; // [rad/s electrical]
|
||||
@@ -96,7 +95,7 @@ public:
|
||||
bool do_checks();
|
||||
float get_inverter_temp();
|
||||
bool update_thermal_limits(float fet_temp);
|
||||
float effective_torque_lim();
|
||||
float effective_current_lim();
|
||||
void log_timing(TimingLog_t log_idx);
|
||||
float phase_current_from_adcval(uint32_t ADCValue);
|
||||
bool measure_phase_resistance(float test_current, float max_voltage);
|
||||
@@ -153,7 +152,6 @@ public:
|
||||
.Id_measured = 0.0f,
|
||||
.I_measured_report_filter_k = 1.0f,
|
||||
.max_allowed_current = 0.0f,
|
||||
.max_allowed_torque = 0.0f,
|
||||
.overcurrent_trip_level = 0.0f,
|
||||
.acim_rotor_flux = 0.0f,
|
||||
.async_phase_vel = 0.0f,
|
||||
|
||||
@@ -376,7 +376,6 @@ interfaces:
|
||||
Id_measured: float32
|
||||
I_measured_report_filter_k: float32
|
||||
max_allowed_current: readonly float32
|
||||
max_allowed_torque: readonly float32
|
||||
overcurrent_trip_level: readonly float32
|
||||
acim_rotor_flux: float32
|
||||
async_phase_vel: readonly float32
|
||||
@@ -497,9 +496,9 @@ interfaces:
|
||||
type: float32
|
||||
doc: Ratio to `vel_limit`. Infinity to disable.
|
||||
vel_ramp_rate: float32
|
||||
current_ramp_rate:
|
||||
torque_ramp_rate:
|
||||
type: float32
|
||||
unit: A / sec
|
||||
unit: Nm / sec
|
||||
homing_speed:
|
||||
type: float32
|
||||
unit: counts/s
|
||||
@@ -692,7 +691,7 @@ valuetypes:
|
||||
PosFilter:
|
||||
MixChannels:
|
||||
TrapTraj:
|
||||
CurrentRamp:
|
||||
TorqueRamp:
|
||||
Mirror:
|
||||
|
||||
|
||||
|
||||
+2
-2
@@ -77,7 +77,7 @@ Possible values are:
|
||||
* `INPUT_MODE_POS_FILTER`
|
||||
* `INPUT_MODE_MIX_CHANNELS`
|
||||
* `INPUT_MODE_TRAP_TRAJ`
|
||||
* `INPUT_MODE_CURRENT_RAMP`
|
||||
* `INPUT_MODE_TORQUE_RAMP`
|
||||
* `INPUT_MODE_MIRROR`
|
||||
|
||||
For more information, see [input_modes](input_modes.md).
|
||||
@@ -97,7 +97,7 @@ Possible values are:
|
||||
* `INPUT_MODE_POS_FILTER`
|
||||
* `INPUT_MODE_MIX_CHANNELS`
|
||||
* `INPUT_MODE_TRAP_TRAJ`
|
||||
* `INPUT_MODE_CURRENT_RAMP`
|
||||
* `INPUT_MODE_TORQUE_RAMP`
|
||||
* `INPUT_MODE_MIRROR`
|
||||
|
||||
## System monitoring commands
|
||||
|
||||
@@ -348,7 +348,7 @@ You can now control the velocity with `axis.controller.input_vel = 5000` [count/
|
||||
|
||||
### Torque control
|
||||
Set `axis.controller.config.control_mode = CONTROL_MODE_CURRENT_CONTROL`.<br>
|
||||
You can now control the torque with `axis.controller.input_torque = 3` [Nm].
|
||||
You can now control the torque with `axis.controller.input_torque = 0.1` [Nm].
|
||||
|
||||
Note: If you exceed `vel_limit` in current control mode, the current is reduced. To disable this, set `axis.controller.enable_current_mode_vel_limit = False`.
|
||||
|
||||
|
||||
+4
-4
@@ -13,7 +13,7 @@ The Input Modes currently valid are:
|
||||
* `INPUT_MODE_POS_FILTER`
|
||||
* `INPUT_MODE_MIX_CHANNELS`
|
||||
* `INPUT_MODE_TRAP_TRAJ`
|
||||
* `INPUT_MODE_CURRENT_RAMP`
|
||||
* `INPUT_MODE_TORQUE_RAMP`
|
||||
* `INPUT_MODE_MIRROR`
|
||||
|
||||
---
|
||||
@@ -85,11 +85,11 @@ Implementes an online trapezoidal trajectory planner.
|
||||
### Valid Control Modes:
|
||||
* `CONTROL_MODE_POSITION_CONTROL`
|
||||
|
||||
## INPUT_MODE_CURRENT_RAMP
|
||||
Ramp a current command from the current value to the target value.
|
||||
## INPUT_MODE_TORQUE_RAMP
|
||||
Ramp a torque command from the current value to the target value.
|
||||
|
||||
### Configuration Values:
|
||||
* `<axis>.controller.config.current_ramp_rate`
|
||||
* `<axis>.controller.config.torque_ramp_rate`
|
||||
|
||||
### Valid Inputs:
|
||||
* `input_torque`
|
||||
|
||||
Vendored
+1
-1
@@ -9,7 +9,7 @@
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"stopOnEntry": true,
|
||||
"pythonPath": "${config:python.interpreterPath}",
|
||||
"pythonPath": "${command:python.pythonPath}",
|
||||
"program": "${file}",
|
||||
"cwd": "${workspaceRoot}",
|
||||
"env": {},
|
||||
|
||||
Reference in New Issue
Block a user