GKD.RoboCtrl
RoboMaster Linux 电控:异步 IO、设备驱动与机器人控制
载入中...
搜索中...
未找到
gkd_sentry_gimbal.cpp
1#include "device/gimbal/gkd_sentry_gimbal.hpp"
2#include "core/async.hpp"
3#include "device/imu/serial_imu.hpp"
4#include "device/motor/lookup.hpp"
5
6using namespace roboctrl;
7using namespace roboctrl::device;
8
9ROBOCTRL_REGISTER_GIMBAL("device.gkd_sentry_gimbal.v1", roboctrl::device::gkd_sentry_gimbal);
10ROBOCTRL_REGISTER_GIMBAL("device.standard_imu_2axis_gimbal.v1", roboctrl::device::gkd_sentry_gimbal);
11ROBOCTRL_REGISTER_GIMBAL("ctrl.standard_imu_2axis_gimbal.v1", roboctrl::device::gkd_sentry_gimbal);
12
13void gkd_sentry_gimbal::reset_controllers() {
14 yaw_angle_pid_.clean(); pitch_angle_pid_.clean(); yaw_relative_pid_.clean();
15 yaw_rate_pid_.clean(); pitch_rate_pid_.clean();
16}
17
18void gkd_sentry_gimbal::hold() {
19 yaw_target_ = measured_yaw_;
20 pitch_target_ = std::clamp(measured_pitch_, info_.pitch_min, info_.pitch_max);
21}
22
24 enabled = enabled && !async::shutdown_requested();
25 if (enabled_ != enabled) {
26 reset_controllers();
27 settle_.reset();
28 initialized_ = false;
29 targets_initialized_ = false;
30 }
31 enabled_ = enabled;
32 if (!enabled) drive_fault_latched_ = false;
33 // Native velocity control can hold torque at zero speed. Only the valid
34 // update path may enable it after checking dependency/calibration gates.
35 if (yaw_motor_ && (!enabled || info_.yaw_current_control)) yaw_motor_->set_enabled(enabled);
36 if (pitch_motor_ && (!enabled || info_.pitch_current_control)) pitch_motor_->set_enabled(enabled);
37}
38
40 if (recentering_ != enabled) {
41 reset_controllers();
42 settle_.reset();
43 if (enabled) initialized_ = false;
44 else hold();
45 }
46 recentering_ = enabled;
47}
48
50 if (!std::isfinite(dt) || dt <= 0 || dt > std::chrono::duration<fp32>(info_.control_time * 5).count()) {
51 reset_controllers();
52 settle_.reset();
53 dt = 0;
54 }
55 if (yaw_motor_->faulted() || (pitch_motor_ && pitch_motor_->faulted()))
56 drive_fault_latched_ = true;
57 const auto angle = imu_->angle();
58 const auto gyro = imu_->gyro();
59 const auto motor_angle = yaw_motor_->angle();
60 const fp32 raw_relative = motor_angle - info_.yaw_zero;
61 const bool finite_feedback = std::isfinite(angle.yaw) && std::isfinite(angle.pitch) &&
62 std::isfinite(angle.roll) && std::isfinite(raw_relative) &&
63 std::isfinite(gyro.x) && std::isfinite(gyro.y) && std::isfinite(gyro.z);
64 const fp32 projected_yaw_rate = finite_feedback ? compensated_yaw_rate(angle.pitch, gyro) : 0.0f;
65 online_ = finite_feedback && std::isfinite(projected_yaw_rate) &&
66 !drive_fault_latched_ && !imu_->offline() && !yaw_motor_->offline() &&
67 (!pitch_motor_ || !pitch_motor_->offline());
68 // Publish only a complete valid snapshot; hold/debug telemetry keep the last
69 // finite pose while invalid feedback clears readiness and actuator outputs.
70 if (online_) {
71 measured_yaw_ = angle.yaw;
72 measured_pitch_ = angle.pitch;
73 relative_yaw_ = utils::rad_format(raw_relative);
74 yaw_rate_ = projected_yaw_rate;
75 }
76
77 if (!online_) {
78 targets_initialized_ = initialized_ = false;
79 settle_.reset();
80 }
81 if (!targets_initialized_ || !enabled_) {
82 hold();
83 targets_initialized_ = online_;
84 }
85 const bool calibration_blocked = recentering_ && info_.recenter_on_enable &&
86 !info_.yaw_zero_calibrated;
87 if (!enabled_ || !online_ || calibration_blocked) {
88 reset_controllers();
89 // Use the same explicit mode as the active path, so a stale current
90 // command cannot survive a switch to a zero speed target.
91 if (info_.yaw_current_control) co_await yaw_motor_->set_current(0.0f);
92 else {
93 yaw_motor_->set_enabled(false);
94 co_await yaw_motor_->set_angle_speed(0.0f);
95 }
96 if (pitch_motor_) {
97 if (info_.pitch_current_control) co_await pitch_motor_->set_current(0.0f);
98 else {
99 pitch_motor_->set_enabled(false);
100 co_await pitch_motor_->set_angle_speed(0.0f);
101 }
102 }
103 } else {
104 if (!info_.yaw_current_control) yaw_motor_->set_enabled(true);
105 if (pitch_motor_ && !info_.pitch_current_control) pitch_motor_->set_enabled(true);
106 fp32 yaw_speed;
107 if (recentering_ && info_.recenter_on_enable) {
108 yaw_relative_pid_.update(0.0f, relative_yaw_, dt);
109 yaw_speed = info_.yaw_recenter_direction * yaw_relative_pid_.state();
110 pitch_target_ = info_.init_pitch;
111 initialized_ = settle_.update(enabled_, online_, relative_yaw_,
112 pitch_motor_ ? utils::rad_format(info_.init_pitch - measured_pitch_) : 0.0f,
113 info_.init_tolerance, std::chrono::duration<fp32>(info_.init_settle_time).count(), dt);
114 yaw_target_ = measured_yaw_;
115 } else {
116 yaw_angle_pid_.update(yaw_target_, measured_yaw_, dt);
117 yaw_speed = info_.yaw_angle_direction * yaw_angle_pid_.state();
118 initialized_ = true;
119 }
120 // Motor output directions belong to the drive command, not the
121 // physical feedback, whose sign is configured once at the IMU.
122 if (info_.yaw_current_control) {
123 yaw_rate_pid_.update(yaw_speed, yaw_rate_, dt);
124 co_await yaw_motor_->set_current(info_.yaw_direction * yaw_rate_pid_.state());
125 } else co_await yaw_motor_->set_angle_speed(info_.yaw_direction * yaw_speed);
126 if (pitch_motor_) {
127 pitch_angle_pid_.update(pitch_target_, measured_pitch_, dt);
128 if (info_.pitch_current_control) {
129 pitch_rate_pid_.update(pitch_angle_pid_.state(), gyro.y, dt);
130 co_await pitch_motor_->set_current(info_.pitch_direction * pitch_rate_pid_.state());
131 } else co_await pitch_motor_->set_angle_speed(info_.pitch_direction * pitch_angle_pid_.state());
132 }
133 }
134}
135
136roboctrl::awaitable<void> gkd_sentry_gimbal::task() {
137 auto previous = std::chrono::steady_clock::now();
138 while (true) {
139 const auto now = std::chrono::steady_clock::now();
140 const fp32 dt = std::chrono::duration<fp32>(now - previous).count();
141 previous = now;
142 co_await update(dt);
143 co_await wait_for(info_.control_time);
144 }
145}
146
147bool gkd_sentry_gimbal::init(const info_type& info) {
148 auto& imu = roboctrl::get<serial_imu>(info.imu_key);
149 auto& yaw = find_motor(info.yaw_motor_type, info.yaw_motor_key);
150 auto* pitch = info.yaw_only ? nullptr : &find_motor(info.pitch_motor_type, info.pitch_motor_key);
151 return init(info, imu, yaw, pitch);
152}
153
154bool gkd_sentry_gimbal::init(const info_type& info, imu_base& imu, motor_base& yaw, motor_base* pitch) {
155 if (started_ || (!info.yaw_only && !pitch)) return false;
156 info_ = info;
157 imu_ = &imu;
158 yaw_motor_ = &yaw;
159 pitch_motor_ = info.yaw_only ? nullptr : pitch;
160 if ((info.yaw_current_control && !yaw_motor_->supports_current_control()) ||
161 (pitch_motor_ && info.pitch_current_control && !pitch_motor_->supports_current_control())) {
162 log_error("Gimbal requested an unsupported current control mode");
163 return false;
164 }
165 yaw_angle_pid_ = utils::rad_pid{info.yaw_angle_pid};
166 pitch_angle_pid_ = utils::rad_pid{info.pitch_angle_pid};
167 yaw_relative_pid_ = utils::rad_pid{info.yaw_relative_pid};
168 yaw_rate_pid_ = utils::linear_pid{info.yaw_rate_pid};
169 pitch_rate_pid_ = utils::linear_pid{info.pitch_rate_pid};
170 return true;
171}
172
173void gkd_sentry_gimbal::start() {
174 if (started_) return;
175 started_ = true;
176 roboctrl::spawn(task());
177}
异步任务上下文组件。
void set_enabled(bool v) override
启用或禁用云台输出。
fp32 pitch() const override
获取当前 pitch 姿态,单位 rad。
fp32 yaw() const override
获取当前 yaw 姿态,单位 rad。
void log_error(std::format_string< Args... > fmt, Args &&...args) const
输出error日志
Definition logger.h:238
awaitable< void > wait_for(const duration &duration)
协程任务等待。
Definition async.hpp:262
auto spawn(task_context::task_type &&task)
添加一个协程任务到全局任务上下文中执行。
Definition async.hpp:191
asio::awaitable< T > awaitable
协程任务类型。
Definition async.hpp:46
bool shutdown_requested()
查询全局任务上下文是否已经进入停机流程。
Definition async.hpp:226
fp32 compensated_yaw_rate(fp32 pitch, three_axis gyro)
Definition feedback.hpp:7
constexpr fp32 rad_format(fp32 ang)
将角度限制到[-Pi,Pi]范围内
Definition utils.hpp:99
bool offline() const
判断设备是否离线
Definition base.hpp:56
云台初始化参数,包括 IMU、电机和角度限制。
Definition base.hpp:25
IMU 基类,封装常见数据通道。
Definition base.hpp:36
euler_angle angle() const
获取欧拉角。(rad)
Definition base.hpp:49
three_axis gyro() const
获取三轴角速度。(rad/s)
Definition base.hpp:47
virtual bool faulted() const
Definition base.hpp:47
virtual awaitable< void > set_angle_speed(fp32 target)
Definition base.hpp:39
virtual awaitable< void > set_current(fp32)
Definition base.hpp:41
virtual void set_enabled(bool enabled)
Definition base.hpp:60
fp32 angle() const
获取电机角度(单位为rad)
Definition base.hpp:67
PID 控制器基础模板。
Definition pid.h:22
void clean()
清空积分项、误差缓存与输出。
Definition pid.h:106
T state() const
获取最新的控制输出。
Definition pid.h:116
void update(T current, T dt)
根据当前值和采样周期更新 PID 输出。
Definition pid.h:67
float fp32
单精度浮点别名。
Definition utils.hpp:22