halx_driver
読み取り中…
検索中…
一致する文字列を見つけられません
cyber_gear.hpp
[詳解]
1#pragma once
2
3#include <algorithm>
4#include <array>
5#include <cmath>
6#include <cstdint>
7#include <cstring>
8#include <numbers>
9#include <optional>
10#include <utility>
11
12#include <halx/core.hpp>
13#include <halx/peripheral/can.hpp>
14
15namespace halx::driver {
16
17enum class CyberGearRunMode : uint8_t {
19 POSITION = 0x01,
20 SPEED = 0x02,
21 CURRENT = 0x03,
22};
23
24enum class CyberGearParameter : uint16_t {
25 RUN_MODE = 0x7005,
26 IQ_REF = 0x7006,
27 SPD_REF = 0x700A,
28 LIMIT_TORQUE = 0x700B,
29 CUR_KP = 0x7010,
30 CUR_KI = 0x7011,
31 CUR_FILT_GAIN = 0x7014,
32 LOC_REF = 0x7016,
33 LIMIT_SPD = 0x7017,
34 LIMIT_CUR = 0x7018,
35 MECH_POS = 0x7019,
36 IQF = 0x701A,
37 MECH_VEL = 0x701B,
38 VBUS = 0x701C,
39 ROTATION = 0x701D,
40 LOC_KP = 0x701E,
41 SPD_KP = 0x701F,
42 SPD_KI = 0x7020,
43};
44
46 uint8_t motor_can_id;
47 uint8_t fault;
48 uint8_t mode;
49 float angle;
50 float velocity;
51 float torque;
53};
54
55class CyberGear {
56public:
57 CyberGear(peripheral::CanBase &can, uint8_t motor_can_id, uint8_t host_can_id)
58 : can_{can}, motor_can_id_{motor_can_id}, master_can_id_{host_can_id} {
59 auto filter_index = can_.attach_rx_queue(
60 {static_cast<uint32_t>(motor_can_id_ << 8), 0x800FF00, true},
61 rx_queue_);
62 if (!filter_index) {
63 std::terminate();
64 }
65 filter_index_ = *filter_index;
66 }
67
68 ~CyberGear() { can_.detach_rx_filter(filter_index_); }
69
70 std::optional<CyberGearFeedback> set_operation_control(float torque,
71 float angle,
72 float velocity,
73 float kp, float kd) {
74 uint16_t torque_int =
75 std::clamp((torque + 12.0f) / 24.0f * 65535.0f, 0.0f, 65535.0f);
76 uint16_t angle_int =
77 std::clamp((angle + 4.0f * static_cast<float>(std::numbers::pi)) /
78 (8.0f * static_cast<float>(std::numbers::pi)) * 65535.0f,
79 0.0f, 65535.0f);
80 uint16_t velocity_int =
81 std::clamp((velocity + 30.0f) / 60.0f * 65535.0f, 0.0f, 65535.0f);
82 uint16_t kp_int = std::clamp(kp / 500.0f * 65535.0f, 0.0f, 65535.0f);
83 uint16_t kd_int = std::clamp(kd / 5.0f * 65535.0f, 0.0f, 65535.0f);
84
85 CyberGearMessage msg;
86 msg.type = CommunicationType::TYPE_1;
87 msg.target_address = motor_can_id_;
88 msg.data1[0] = (angle_int >> 8) & 0xFF;
89 msg.data1[1] = angle_int & 0xFF;
90 msg.data1[2] = (velocity_int >> 8) & 0xFF;
91 msg.data1[3] = velocity_int & 0xFF;
92 msg.data1[4] = (kp_int >> 8) & 0xFF;
93 msg.data1[5] = kp_int & 0xFF;
94 msg.data1[6] = (kd_int >> 8) & 0xFF;
95 msg.data1[7] = kd_int & 0xFF;
96 msg.data2 = torque_int;
97 auto res = send_message(msg);
98 if (!res) {
99 return std::nullopt;
100 }
101 return to_cyber_gear_motor_feedback(*res);
102 }
103
104 std::optional<CyberGearFeedback> enable() {
105 CyberGearMessage msg{
106 CommunicationType::TYPE_3, motor_can_id_, {}, master_can_id_};
107 auto res = send_message(msg);
108 if (!res) {
109 return std::nullopt;
110 }
111 return to_cyber_gear_motor_feedback(*res);
112 }
113
114 std::optional<CyberGearFeedback> stop(bool clear_fault) {
115 CyberGearMessage msg{CommunicationType::TYPE_4,
116 motor_can_id_,
117 {static_cast<uint8_t>(clear_fault)},
118 master_can_id_};
119 auto res = send_message(msg);
120 if (!res) {
121 return std::nullopt;
122 }
123 return to_cyber_gear_motor_feedback(*res);
124 }
125
126 std::optional<CyberGearFeedback> set_position_to_mechanical_zero() {
127 CyberGearMessage msg{
128 CommunicationType::TYPE_6, motor_can_id_, {1}, master_can_id_};
129 auto res = send_message(msg);
130 if (!res) {
131 return std::nullopt;
132 }
133 return to_cyber_gear_motor_feedback(*res);
134 }
135
136 template <class T>
137 std::optional<T> read_parameter(CyberGearParameter parameter) {
138 uint16_t index = std::to_underlying(parameter);
139 CyberGearMessage msg{
140 CommunicationType::TYPE_17,
141 motor_can_id_,
142 {static_cast<uint8_t>(index), static_cast<uint8_t>(index >> 8)},
143 master_can_id_};
144 auto res = send_message(msg);
145 if (!res) {
146 return std::nullopt;
147 }
148 if (res->type != CommunicationType::TYPE_17) {
149 return std::nullopt;
150 }
151 T data;
152 std::memcpy(&data, &res->data1[4], sizeof(T));
153 return data;
154 }
155
156 template <class T>
157 std::optional<CyberGearFeedback> write_parameter(CyberGearParameter parameter,
158 T data) {
159 uint16_t index = std::to_underlying(parameter);
160 CyberGearMessage msg{
161 CommunicationType::TYPE_18,
162 motor_can_id_,
163 {static_cast<uint8_t>(index), static_cast<uint8_t>(index >> 8)},
164 master_can_id_};
165 std::memcpy(&msg.data1[4], &data, sizeof(T));
166 auto res = send_message(msg);
167 if (!res) {
168 return std::nullopt;
169 }
170 return to_cyber_gear_motor_feedback(*res);
171 }
172
173private:
174 enum class CommunicationType : uint8_t {
175 TYPE_0 = 0,
176 TYPE_1 = 1,
177 TYPE_2 = 2,
178 TYPE_3 = 3,
179 TYPE_4 = 4,
180 TYPE_6 = 6,
181 TYPE_7 = 7,
182 TYPE_17 = 17,
183 TYPE_18 = 18,
184 TYPE_21 = 21,
185 TYPE_22 = 22,
186 };
187
188 struct CyberGearMessage {
189 CommunicationType type;
190 uint8_t target_address;
191 alignas(alignof(uintptr_t)) std::array<uint8_t, 8> data1;
192 uint16_t data2;
193 };
194
195 peripheral::CanBase &can_;
196 size_t filter_index_;
197 core::RingBuffer<peripheral::CanMessage> rx_queue_{8};
198 uint8_t motor_can_id_;
199 uint8_t master_can_id_;
200
201 static inline peripheral::CanMessage
202 to_can_message(const CyberGearMessage &msg) {
203 return {static_cast<uint32_t>(std::to_underlying(msg.type) << 24 |
204 msg.data2 << 8 | msg.target_address),
205 true, 8, msg.data1};
206 }
207
208 static inline std::optional<CyberGearMessage>
209 to_cyber_gear_message(const peripheral::CanMessage &msg) {
210 CyberGearMessage cyber_gear_msg;
211 uint8_t type = (msg.id >> 24) & 0x1F;
212 cyber_gear_msg.target_address = msg.id & 0xFF;
213 cyber_gear_msg.data1 = msg.data;
214 cyber_gear_msg.data2 = (msg.id >> 8) & 0xFFFF;
215
216 switch (type) {
217 case 0:
218 cyber_gear_msg.type = CommunicationType::TYPE_0;
219 break;
220 case 1:
221 cyber_gear_msg.type = CommunicationType::TYPE_1;
222 break;
223 case 2:
224 cyber_gear_msg.type = CommunicationType::TYPE_2;
225 break;
226 case 3:
227 cyber_gear_msg.type = CommunicationType::TYPE_3;
228 break;
229 case 4:
230 cyber_gear_msg.type = CommunicationType::TYPE_4;
231 break;
232 case 6:
233 cyber_gear_msg.type = CommunicationType::TYPE_6;
234 break;
235 case 7:
236 cyber_gear_msg.type = CommunicationType::TYPE_7;
237 break;
238 case 17:
239 cyber_gear_msg.type = CommunicationType::TYPE_17;
240 break;
241 case 18:
242 cyber_gear_msg.type = CommunicationType::TYPE_18;
243 break;
244 case 21:
245 cyber_gear_msg.type = CommunicationType::TYPE_21;
246 break;
247 case 22:
248 cyber_gear_msg.type = CommunicationType::TYPE_22;
249 break;
250 default:
251 return std::nullopt;
252 }
253 return cyber_gear_msg;
254 }
255
256 static inline std::optional<CyberGearFeedback>
257 to_cyber_gear_motor_feedback(const CyberGearMessage &msg) {
258 if (msg.type != CommunicationType::TYPE_2) {
259 return std::nullopt;
260 }
261
262 CyberGearFeedback feedback;
263 feedback.motor_can_id = msg.data2 & 0xFF;
264 feedback.fault = (msg.data2 >> 8) & 0x3F;
265 feedback.mode = (msg.data2 >> 14) & 0x3;
266 feedback.angle = ((msg.data1[0] << 8) | msg.data1[1]) / 65535.0f * 8.0f *
267 std::numbers::pi -
268 4.0f * std::numbers::pi;
269 feedback.velocity =
270 ((msg.data1[2] << 8) | msg.data1[3]) / 65535.0f * 60.0f - 30.0f;
271 feedback.torque =
272 ((msg.data1[4] << 8) | msg.data1[5]) / 65535.0f * 24.0f - 12.0f;
273 feedback.temperature = ((msg.data1[6] << 8) | msg.data1[7]) / 10.0f;
274 return feedback;
275 }
276
277 std::optional<CyberGearMessage> send_message(const CyberGearMessage &msg) {
278 rx_queue_.clear();
279 if (!can_.transmit(to_can_message(msg), 5)) {
280 return std::nullopt;
281 }
282 auto can_msg = rx_queue_.pop(5);
283 if (!can_msg) {
284 return std::nullopt;
285 }
286 return to_cyber_gear_message(*can_msg);
287 }
288};
289
290} // namespace halx::driver
std::optional< CyberGearFeedback > set_position_to_mechanical_zero()
Definition cyber_gear.hpp:126
std::optional< CyberGearFeedback > stop(bool clear_fault)
Definition cyber_gear.hpp:114
std::optional< T > read_parameter(CyberGearParameter parameter)
Definition cyber_gear.hpp:137
CyberGear(peripheral::CanBase &can, uint8_t motor_can_id, uint8_t host_can_id)
Definition cyber_gear.hpp:57
~CyberGear()
Definition cyber_gear.hpp:68
std::optional< CyberGearFeedback > enable()
Definition cyber_gear.hpp:104
std::optional< CyberGearFeedback > write_parameter(CyberGearParameter parameter, T data)
Definition cyber_gear.hpp:157
std::optional< CyberGearFeedback > set_operation_control(float torque, float angle, float velocity, float kp, float kd)
Definition cyber_gear.hpp:70
Definition amt21.hpp:10
CyberGearParameter
Definition cyber_gear.hpp:24
@ CUR_KP
Definition cyber_gear.hpp:29
@ LIMIT_SPD
Definition cyber_gear.hpp:33
@ LIMIT_CUR
Definition cyber_gear.hpp:34
@ VBUS
Definition cyber_gear.hpp:38
@ CUR_KI
Definition cyber_gear.hpp:30
@ SPD_KI
Definition cyber_gear.hpp:42
@ LOC_REF
Definition cyber_gear.hpp:32
@ IQF
Definition cyber_gear.hpp:36
@ ROTATION
Definition cyber_gear.hpp:39
@ CUR_FILT_GAIN
Definition cyber_gear.hpp:31
@ RUN_MODE
Definition cyber_gear.hpp:25
@ IQ_REF
Definition cyber_gear.hpp:26
@ LOC_KP
Definition cyber_gear.hpp:40
@ SPD_REF
Definition cyber_gear.hpp:27
@ MECH_POS
Definition cyber_gear.hpp:35
@ MECH_VEL
Definition cyber_gear.hpp:37
@ SPD_KP
Definition cyber_gear.hpp:41
@ LIMIT_TORQUE
Definition cyber_gear.hpp:28
CyberGearRunMode
Definition cyber_gear.hpp:17
@ SPEED
Definition cyber_gear.hpp:20
@ POSITION
Definition cyber_gear.hpp:19
@ OPERATION_CONTROL
Definition cyber_gear.hpp:18
@ CURRENT
Definition cyber_gear.hpp:21
Definition cyber_gear.hpp:45
uint8_t motor_can_id
Definition cyber_gear.hpp:46
float angle
Definition cyber_gear.hpp:49
float torque
Definition cyber_gear.hpp:51
float velocity
Definition cyber_gear.hpp:50
float temperature
Definition cyber_gear.hpp:52
uint8_t fault
Definition cyber_gear.hpp:47
uint8_t mode
Definition cyber_gear.hpp:48