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},
65 filter_index_ = *filter_index;
75 std::clamp((torque + 12.0f) / 24.0f * 65535.0f, 0.0f, 65535.0f);
77 std::clamp((angle + 4.0f *
static_cast<float>(std::numbers::pi)) /
78 (8.0f *
static_cast<float>(std::numbers::pi)) * 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);
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);
101 return to_cyber_gear_motor_feedback(*res);
104 std::optional<CyberGearFeedback>
enable() {
105 CyberGearMessage msg{
106 CommunicationType::TYPE_3, motor_can_id_, {}, master_can_id_};
107 auto res = send_message(msg);
111 return to_cyber_gear_motor_feedback(*res);
114 std::optional<CyberGearFeedback>
stop(
bool clear_fault) {
115 CyberGearMessage msg{CommunicationType::TYPE_4,
117 {
static_cast<uint8_t
>(clear_fault)},
119 auto res = send_message(msg);
123 return to_cyber_gear_motor_feedback(*res);
127 CyberGearMessage msg{
128 CommunicationType::TYPE_6, motor_can_id_, {1}, master_can_id_};
129 auto res = send_message(msg);
133 return to_cyber_gear_motor_feedback(*res);
138 uint16_t index = std::to_underlying(parameter);
139 CyberGearMessage msg{
140 CommunicationType::TYPE_17,
142 {
static_cast<uint8_t
>(index),
static_cast<uint8_t
>(index >> 8)},
144 auto res = send_message(msg);
148 if (res->type != CommunicationType::TYPE_17) {
152 std::memcpy(&data, &res->data1[4],
sizeof(T));
159 uint16_t index = std::to_underlying(parameter);
160 CyberGearMessage msg{
161 CommunicationType::TYPE_18,
163 {
static_cast<uint8_t
>(index),
static_cast<uint8_t
>(index >> 8)},
165 std::memcpy(&msg.data1[4], &data,
sizeof(T));
166 auto res = send_message(msg);
170 return to_cyber_gear_motor_feedback(*res);
174 enum class CommunicationType : uint8_t {
188 struct CyberGearMessage {
189 CommunicationType type;
190 uint8_t target_address;
191 alignas(
alignof(uintptr_t)) std::array<uint8_t, 8> data1;
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_;
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),
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;
218 cyber_gear_msg.type = CommunicationType::TYPE_0;
221 cyber_gear_msg.type = CommunicationType::TYPE_1;
224 cyber_gear_msg.type = CommunicationType::TYPE_2;
227 cyber_gear_msg.type = CommunicationType::TYPE_3;
230 cyber_gear_msg.type = CommunicationType::TYPE_4;
233 cyber_gear_msg.type = CommunicationType::TYPE_6;
236 cyber_gear_msg.type = CommunicationType::TYPE_7;
239 cyber_gear_msg.type = CommunicationType::TYPE_17;
242 cyber_gear_msg.type = CommunicationType::TYPE_18;
245 cyber_gear_msg.type = CommunicationType::TYPE_21;
248 cyber_gear_msg.type = CommunicationType::TYPE_22;
253 return cyber_gear_msg;
256 static inline std::optional<CyberGearFeedback>
257 to_cyber_gear_motor_feedback(
const CyberGearMessage &msg) {
258 if (msg.type != CommunicationType::TYPE_2) {
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 *
268 4.0f * std::numbers::pi;
270 ((msg.data1[2] << 8) | msg.data1[3]) / 65535.0f * 60.0f - 30.0f;
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;
277 std::optional<CyberGearMessage> send_message(
const CyberGearMessage &msg) {
279 if (!can_.transmit(to_can_message(msg), 5)) {
282 auto can_msg = rx_queue_.pop(5);
286 return to_cyber_gear_message(*can_msg);
std::optional< CyberGearFeedback > set_operation_control(float torque, float angle, float velocity, float kp, float kd)
Definition cyber_gear.hpp:70