pub trait Controller {
type Error: Error + Send + 'static;
// Required method
fn tick(
&mut self,
current: &JointArray<Rad>,
dt: Duration,
) -> Result<JointArray<NewtonMeter>, Self::Error>;
// Provided methods
fn on_time_jump(&mut self, _dt: Duration) -> Result<(), Self::Error> { ... }
fn reset(&mut self) -> Result<(), Self::Error> { ... }
}Expand description
Required Associated Types§
Required Methods§
Sourcefn tick(
&mut self,
current: &JointArray<Rad>,
dt: Duration,
) -> Result<JointArray<NewtonMeter>, Self::Error>
fn tick( &mut self, current: &JointArray<Rad>, dt: Duration, ) -> Result<JointArray<NewtonMeter>, Self::Error>
计算一步控制输出
§参数
current: 当前关节位置dt: 时间步长(自上次tick以来的时间)
§返回
Ok(output): 关节力矩命令Err(e): 控制器内部错误
§注意
dt可能会被钳位(clamped),不一定等于实际时间- 如果
dt被钳位,on_time_jump()会先被调用 - 输出力矩应该被钳位到安全范围内
§示例
fn tick(
&mut self,
current: &JointArray<Rad>,
dt: Duration,
) -> Result<JointArray<NewtonMeter>, Self::Error> {
// 1. 计算误差
let error = self.compute_error(current);
// 2. 更新内部状态(积分、微分等)
self.update_state(&error, dt);
// 3. 计算输出
let output = self.compute_output(&error, dt);
// 4. 钳位输出到安全范围
Ok(output.map(|t| t.clamp(NewtonMeter(-50.0), NewtonMeter(50.0))))
}Provided Methods§
Sourcefn on_time_jump(&mut self, _dt: Duration) -> Result<(), Self::Error>
fn on_time_jump(&mut self, _dt: Duration) -> Result<(), Self::Error>
处理时间跳变
当检测到 dt 超过预期(通常是由于系统卡顿、线程调度延迟等),
此方法会被调用,允许控制器重置或调整内部状态。
§参数
dt: 实际经过的时间(未钳位前)
§默认实现
默认实现不做任何事情(Ok(()))。
§⚠️ 重要提示
对于 时间敏感 的控制器(如 PID),强烈建议 覆盖此方法:
§✅ 应该重置的状态
- 微分项(D term):
last_error等用于计算导数的状态- 原因:大的
dt会导致(error - last_error) / dt计算错误
- 原因:大的
§❌ 不应该清零的状态
- 积分项(I term): 累积误差
- 原因:机械臂可能依赖积分项对抗重力
- 后果:清零会导致机械臂瞬间下坠(Sagging)
§示例
struct PidController {
integral: JointArray<f64>, // 积分项
last_error: JointArray<f64>, // 用于计算微分
}
impl Controller for PidController {
type Error = std::io::Error;
fn tick(&mut self, current: &JointArray<Rad>, dt: Duration)
-> Result<JointArray<NewtonMeter>, Self::Error> {
// ... 实现 ...
Ok(JointArray::from([NewtonMeter(0.0); 6]))
}
fn on_time_jump(&mut self, _dt: Duration) -> Result<(), Self::Error> {
// ✅ 重置微分项
self.last_error = JointArray::from([0.0; 6]);
// ❌ 不要清零积分项!
// self.integral = JointArray::from([0.0; 6]); // 会导致机械臂下坠
Ok(())
}
}§何时调用
通常在 run_controller() 中,当检测到 dt 超过阈值时:
ⓘ
if real_dt > max_dt {
controller.on_time_jump(real_dt)?;
dt = max_dt; // 钳位后传入 tick()
}