GKD.RoboCtrl
RoboMaster Linux 电控:异步 IO、设备驱动与机器人控制
载入中...
搜索中...
未找到
shoot.cpp
1#include "ctrl/shoot.h"
2#include "device/motor/dji.h"
3#include "device/referee/referee.h"
4#include <cmath>
5#include <stdexcept>
6
7using namespace roboctrl::ctrl;
8
9namespace {
10
11bool trigger_jammed(roboctrl::fp32 current, roboctrl::fp32 rpm,
12 roboctrl::fp32 current_threshold, roboctrl::fp32 speed_threshold)
13{
14 return std::isfinite(current) && std::isfinite(rpm) &&
15 std::fabs(current) > current_threshold && std::fabs(rpm) < speed_threshold;
16}
17
18bool trigger_feed_allowed(bool firing, bool friction_enabled, bool friction_ready,
19 bool motors_online, bool jam_hold_active)
20{
21 return firing && friction_enabled && friction_ready && motors_online && !jam_hold_active;
22}
23
24bool referee_allows_feed(unsigned caliber)
25{
26 auto& referee = roboctrl::get<roboctrl::device::referee>();
27 if (!referee.configured() || referee.offline()) return false;
28 const auto& data = referee.data();
29 const auto now = std::chrono::steady_clock::now();
30 const auto timeout = referee.timeout();
31 if (!data.game.fresh(now, timeout) || !data.robot.fresh(now, timeout) ||
32 !data.ammunition.fresh(now, timeout)) return false;
33 return data.game.value.progress == 4 && data.robot.value.hp != 0 &&
34 data.robot.value.shooter_power &&
35 (caliber == 42 ? data.ammunition.value.bullets_42 : data.ammunition.value.bullets_17) > 0;
36}
37
38} // namespace
39
41{
42 return init(info, roboctrl::get<device::dji_motor>(info.left_friction_motor),
43 roboctrl::get<device::dji_motor>(info.right_friction_motor),
44 roboctrl::get<device::dji_motor>(info.trigger_motor));
45}
46
47bool shoot::init(const info_type& info, device::motor_base& left,
49{
50 if (initialized_) throw std::logic_error("shoot already initialized");
51 if (&left == &right || &left == &trigger || &right == &trigger ||
52 !std::isfinite(info.friction_params.acc) || info.friction_params.acc < 0 ||
53 !std::isfinite(info.friction_max_speed) || info.friction_max_speed <= 0 ||
54 !std::isfinite(info.trigger_speed) || !std::isfinite(info.friction_ready_speed) ||
55 info.friction_ready_speed <= 0 || info.friction_ready_speed > info.friction_max_speed ||
56 !std::isfinite(info.jam_current) || info.jam_current < 0 ||
57 !std::isfinite(info.jam_speed) || info.jam_speed < 0 ||
58 info.control_time <= std::chrono::steady_clock::duration::zero() ||
59 info.jam_release_time < std::chrono::steady_clock::duration::zero() ||
60 (info.bullet_caliber != 17 && info.bullet_caliber != 42))
61 throw std::invalid_argument("invalid shoot parameters/bindings");
62 info_ = info;
63 friction_ramp_ = utils::ramp_f{info_.friction_params};
64 left_friction_motor_ = &left;
65 right_friction_motor_ = &right;
66 trigger_motor_ = &trigger;
67 initialized_ = true;
68 set_enabled(false);
69 log_info("Shoot initiated");
70 return true;
71}
72
73void shoot::start()
74{
75 if (started_) return;
76 if (!initialized_) throw std::logic_error("shoot start before init");
77 started_ = true;
79}
80
81void shoot::set_enabled(bool enabled)
82{
83 enabled = enabled && !roboctrl::async::shutdown_requested();
84 enabled_ = enabled && initialized_;
85 if (!enabled_) {
86 firing_ = false;
87 friction_enabled_ = false;
88 fire_permitted_ = false;
89 friction_ramp_.reset();
90 jam_release_at_ = {};
91 }
92 for (auto* motor : {left_friction_motor_, right_friction_motor_, trigger_motor_})
93 if (motor) motor->set_enabled(enabled_);
94}
95
96void shoot::set_firing(bool state)
97{
98 firing_ = enabled_ && state;
99}
100
102{
103 friction_enabled_ = enabled_ && state;
104 if (!friction_enabled_) firing_ = false;
105}
106
108{
109 if (!initialized_) return false;
110 const auto left = left_friction_motor_->linear_speed();
111 const auto right = right_friction_motor_->linear_speed();
112 return std::isfinite(left) && std::isfinite(right) &&
113 std::fabs(left) >= info_.friction_ready_speed &&
114 std::fabs(right) >= info_.friction_ready_speed;
115}
116
117bool shoot::fire_allowed() const
118{
119 if (!enabled_ || !fire_permitted_ || !initialized_ ||
120 !std::isfinite(trigger_motor_->angle_speed()) || !std::isfinite(trigger_motor_->current_feedback_raw())) return false;
121 const bool motors_online = !left_friction_motor_->offline() &&
122 !right_friction_motor_->offline() && !trigger_motor_->offline();
123 return trigger_feed_allowed(firing_, friction_enabled_, friction_ready(), motors_online,
124 std::chrono::steady_clock::now() < jam_release_at_) &&
125 (!info_.enforce_referee || referee_allows_feed(info_.bullet_caliber));
126}
127
129{
130 if (!initialized_) co_return;
131 const bool motors_online = !left_friction_motor_->offline() &&
132 !right_friction_motor_->offline() && !trigger_motor_->offline();
133 if (!enabled_ || !motors_online) {
134 friction_ramp_.reset();
135 co_await left_friction_motor_->set(0);
136 co_await right_friction_motor_->set(0);
137 co_await trigger_motor_->set_angle_speed(0);
138 jam_release_at_ = {};
139 co_return;
140 }
141
142 if (!std::isfinite(dt) || dt < 0 || dt > std::chrono::duration<fp32>(info_.control_time * 5).count()) dt = 0;
143 friction_ramp_.update(friction_enabled_ ? info_.friction_max_speed : 0.0f, dt);
144 co_await left_friction_motor_->set(-friction_ramp_.state());
145 co_await right_friction_motor_->set(friction_ramp_.state());
146
147 const auto now = std::chrono::steady_clock::now();
148 if (firing_ && friction_enabled_ && friction_ready() &&
149 trigger_jammed(trigger_motor_->current_feedback_raw(), trigger_motor_->rpm(), info_.jam_current, info_.jam_speed) &&
150 now >= jam_release_at_) {
151 jam_release_at_ = now + info_.jam_release_time;
152 log_warn("Trigger jam detected; pausing feed");
153 }
154 co_await trigger_motor_->set_angle_speed(fire_allowed() ? info_.trigger_speed : 0.0f);
155}
156
158{
159 auto previous = std::chrono::steady_clock::time_point{};
160 while (true) {
161 const auto now = std::chrono::steady_clock::now();
162 const auto dt = previous == std::chrono::steady_clock::time_point{} ? 0.f :
163 std::chrono::duration<fp32>(now - previous).count();
164 previous = now;
165 co_await update(dt);
166 co_await roboctrl::wait_for(info_.control_time);
167 }
168}
bool friction_ready() const
判断摩擦轮是否达到可发射的准备速度。
Definition shoot.cpp:107
void set_firing(bool state)
请求开始或停止拨弹。
Definition shoot.cpp:96
roboctrl::awaitable< void > task()
周期更新摩擦轮和拨弹电机输出。
Definition shoot.cpp:157
bool init(const info_type &info)
绑定发射器所需电机并初始化内部状态。
Definition shoot.cpp:40
void set_friction_enabled(bool state)
请求启用或停止摩擦轮。
Definition shoot.cpp:101
void set_enabled(bool enabled)
Definition shoot.cpp:81
roboctrl::awaitable< void > update(fp32 dt)
Definition shoot.cpp:128
void log_warn(std::format_string< Args... > fmt, Args &&...args) const
输出warn日志
Definition logger.h:226
void log_info(std::format_string< Args... > fmt, Args &&...args) const
输出info日志
Definition logger.h:214
一阶斜坡控制器 (Ramp)
Definition ramp.hpp:38
void update(T target, T dt) noexcept
更新输出值
Definition ramp.hpp:76
state_type state() const noexcept
获取当前输出状态
Definition ramp.hpp:117
void reset() noexcept
清零输出值
Definition ramp.hpp:105
DJI 电机及分组抽象。
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
auto now()
记录程序启动后的纳秒级时间戳。
Definition utils.hpp:158
发射器和拨弹机构控制。
发射器初始化参数。
Definition shoot.h:25
bool offline() const
判断设备是否离线
Definition base.hpp:56
virtual awaitable< void > set_angle_speed(fp32 target)
Definition base.hpp:39
fp32 linear_speed() const
获取电机线速度(单位为m/s)
Definition base.hpp:95
virtual awaitable< void > set(fp32 target)=0
fp32 angle_speed() const
获取电机角速度(单位为rad/s)
Definition base.hpp:74
fp32 rpm() const
获取电机转速(单位为rpm)
Definition base.hpp:81
float fp32
单精度浮点别名。
Definition utils.hpp:22