GKD.RoboCtrl
载入中...
搜索中...
未找到
dji.cpp
1#include <chrono>
2#include <cstddef>
3#include <cstdint>
4#include <sys/types.h>
5
6#include "device/motor/dji.h"
7#include "core/async.hpp"
9#include "io/base.hpp"
10#include "io/can.h"
11#include "utils/utils.hpp"
12
13using namespace std::chrono_literals;
14using namespace roboctrl::device;
15using namespace roboctrl;
16
18 uint8_t angle_h;
19 uint8_t angle_l;
20 uint8_t speed_h;
21 uint8_t speed_l;
22 uint8_t current_h;
23 uint8_t current_l;
24 uint8_t temperature;
25 uint8_t unused;
26} __attribute__((packed));
27
28constexpr fp32 _rpm_to_rad_s = 2.f * Pi_f / 60.f;
29constexpr fp32 _ecd_8192_to_rad = 2.f * Pi_f / 8192.f;
30
31static std::string __motor_tyep_to_string(dji_motor::type type){
32 switch(type){
33 case roboctrl::device::dji_motor::M2006:
34 return "M2006";
35 case roboctrl::device::dji_motor::M3508:
36 return "M3508";
37 case roboctrl::device::dji_motor::M6020:
38 return "M6020";
39 default:
40 return "Unknown";
41 }
42}
43
45 info_{info}
46{
47 std::fill(motors_.begin(),motors_.end(),nullptr);
48 log_info("Dji Motor Group created on {}",info.can_name);
50}
51
53 for(auto m : motors_){
54 if(m->can_pkg_id() == motor->can_pkg_id()){
55 log_error("motor id conflict:{} and {}",m->desc(),motor->desc());
56 return;
57 }
58 }
59
60 motors_.push_back(motor);
61}
62
63std::pair<uint16_t, uint16_t> dji_motor::can_pkg_id() const {
64 switch(info_.type_) {
65 case M2006:
66 case M3508:
67 if (info_.id >= 1 && info_.id <= 4)
68 return {0x200, static_cast<uint16_t>(info_.id - 1)}; // index: 0..3
69 else if (info_.id >= 5 && info_.id <= 8)
70 return {0x1ff, static_cast<uint16_t>(info_.id - 5)}; // index: 0..3
71 else {
72 log_error("invalid dji motor id: {}", info_.id);
73 return {0x200, 0};
74 }
75 case M6020:
76 if (info_.id >= 1 && info_.id <= 4)
77 return {0x1ff, static_cast<uint16_t>(info_.id - 1)};
78 else if (info_.id >= 5 && info_.id <= 8)
79 return {0x2ff, static_cast<uint16_t>(info_.id - 5)};
80 else {
81 log_error("invalid gm6020 id: {}", info_.id);
82 return {0x1ff, 0};
83 }
84 }
85}
86
87roboctrl::awaitable<void> dji_motor_group::send_command(uint16_t can_id_) {
88 std::array<std::byte,8> data{};
89 bool flag = false;
90
91 for (auto motor : motors_) {
92 if (!motor) continue;
93
94 auto [can_id, index] = motor->can_pkg_id();
95 if (can_id == can_id_) {
96 auto cur = motor->current();
97 std::size_t offset = static_cast<std::size_t>(index) * 2;
98 if (offset + 1 >= data.size()) {
99 log_error("dji current index out of range: id={}, index={}", motor->info_.can_name, index);
100 continue;
101 }
102
103 data[offset] = utils::to_byte(static_cast<uint16_t>(cur) >> 8);
104 data[offset + 1] = utils::to_byte(static_cast<uint16_t>(cur) & 0xff);
105 flag = true;
106 }
107 }
108
109 if (flag)
110 co_await roboctrl::get<io::can>(info_.can_name).send(can_id_, data);
111};
112
114 while(true){
115 co_await send_command(0x1ff);
116 co_await send_command(0x200);
117 co_await send_command(0x2ff);
118
119 co_await wait_for(1ms);
120 }
121}
122
123dji_motor::dji_motor(dji_motor::info_type info)
124 :info_{info},
125 pid_{info.pid_params},
126 motor_base{2ms,info.radius}
127{
128 auto& group = roboctrl::get(dji_motor_group::info_type::make(info.can_name));
129 log_debug("Dji \"{}\" motor {} created on can \"{}\" with pid(p={},i={},d={},max iout={},max out={})",
130 __motor_tyep_to_string(info.type_),
131 info.name,
132 info.can_name,
133 info.pid_params.kp,
134 info.pid_params.ki,
135 info.pid_params.kd,
136 info.pid_params.max_iout,
137 info.pid_params.max_out
138 );
139
140 auto& can = roboctrl::get<io::can>(info_.can_name);
141
143
144 switch(info.type_){
145 case dji_motor::M2006:
146 reduction_ratio_ = 1.f / 36.f;
147 fallback_canid = 0x200 + info.id;
148 break;
149 case dji_motor::M3508:
150 reduction_ratio_ = 1.f / 19.f;
151 fallback_canid = 0x200 + info.id;
152 break;
153 case dji_motor::M6020:
154 reduction_ratio_ = 1.f;
155 fallback_canid = 0x204 + info.id;
156 break;
157 }
158
159 can.on_data(fallback_canid,[this](const _dji_upload_pkg& pkg) -> void{
160 angle_ = _ecd_8192_to_rad * static_cast<float>(utils::make_u16(pkg.angle_h, pkg.angle_l)) ;
161 angle_speed_ = _rpm_to_rad_s * static_cast<float>(utils::make_i16(pkg.speed_h, pkg.speed_l)) * reduction_ratio_;
162 torque_ = utils::make_i16(pkg.current_h, pkg.current_l);
163
164 pid_.update(linear_speed());
165 current_ = pid_.state();
166
167 log_debug("angle:{}, speed:{}, torque:{} ,linear speed:{},target speed:{}",this->angle_,this->angle_speed_,this->torque_,linear_speed(),pid_.target());
168 tick();
169 });
170
171 group.register_motor(this);
173}
174
176 pid_.set_target(speed);
177
178 log_debug("target set to :{}",speed);
179
180 co_return;
181}
182
183roboctrl::awaitable<void> dji_motor::task(){
184 while(true){
185 log_debug("pid output :{}",pid_.state());
186
187 co_await wait_for(info_.control_time);
188 }
189}
异步任务上下文组件。
基于 Linux SocketCAN 的 CAN 总线封装。
dji_motor_group(info_type info)
构造分组。
Definition dji.cpp:44
awaitable< void > task()
与调度器协同的任务,负责读取反馈等。
Definition dji.cpp:113
void register_motor(dji_motor *motor)
注册单个电机到分组内。
Definition dji.cpp:52
DJI 系列电机。
Definition dji.h:24
awaitable< void > set(fp32 speed)
设置目标电流或速度(取决于电调模式)。
Definition dji.cpp:175
void log_error(std::format_string< Args... > fmt, Args &&...args) const
输出error日志
Definition logger.h:238
void log_debug(std::format_string< Args... > fmt, Args &&...args) const
输出debug日志
Definition logger.h:202
void log_info(std::format_string< Args... > fmt, Args &&...args) const
输出info日志
Definition logger.h:214
电机基础组件。
DJI 电机及分组抽象。
IO的基础组件。
awaitable< void > wait_for(const duration &duration)
协程任务等待。
Definition async.hpp:202
auto spawn(task_context::task_type &&task)
添加一个协程任务到全局任务上下文中执行。
Definition async.hpp:151
asio::awaitable< T > awaitable
协程任务类型。
Definition async.hpp:42
设备模块
Definition base.hpp:25
auto get() -> T &
获取单例实例
Definition multiton.hpp:183
constexpr std::byte to_byte(std::integral auto v) noexcept
辅助将整数转换为 std::byte。
Definition utils.hpp:169
constexpr int16_t make_i16(int16_t high, int16_t low) noexcept
将高低字节组合成有符号 16 位整数。
Definition utils.hpp:162
constexpr uint16_t make_u16(uint16_t high, uint16_t low) noexcept
将高低字节组合成无符号 16 位整数。
Definition utils.hpp:155
电机初始化参数。
Definition dji.h:35
分组初始化参数。
Definition dji.h:87
T state() const
获取最新的控制输出。
Definition pid.h:97
void set_target(T target)
设置期望目标。
Definition pid.h:53
常用数值与字节工具集合。
constexpr auto Pi_f
单精度浮点类型的 Pi 常量。
Definition utils.hpp:34
float fp32
单精度浮点别名。
Definition utils.hpp:22