53 UnitreeGo(peripheral::UartBase &uart) : uart_{uart} {}
56 auto tx_buf = to_uart_buf(command);
57 std::array<uint8_t, 16> rx_buf;
59 if (!uart_.transmit(tx_buf.data(), tx_buf.size(), 10)) {
62 if (!uart_.receive(rx_buf.data(), rx_buf.size(), 10)) {
65 return to_unitree_go_feedback(rx_buf);
69 peripheral::UartBase &uart_;
71 static inline std::array<uint8_t, 17>
73 int16_t tau_set = std::clamp(command.
torque, -127.99f, 127.99f) * 256.0f;
74 int16_t omega_set = std::clamp(command.
radps, -804.0f, 804.0f) /
75 (2.0f * std::numbers::pi) * 256.0f;
76 int32_t theta_set = command.
rad / (2.0f * std::numbers::pi) * 32768.0f;
77 int16_t k_pos = std::clamp(command.
kp, 0.0f, 25.599f) * 1280.0f;
78 int16_t k_spd = std::clamp(command.
kd, 0.0f, 25.599f) * 1280.0f;
80 std::array<uint8_t, 17> buf;
83 buf[2] = std::to_underlying(command.
mode) << 4 | command.
id;
84 buf[3] = tau_set & 0xFF;
85 buf[4] = (tau_set >> 8) & 0xFF;
86 buf[5] = omega_set & 0xFF;
87 buf[6] = (omega_set >> 8) & 0xFF;
88 buf[7] = theta_set & 0xFF;
89 buf[8] = (theta_set >> 8) & 0xFF;
90 buf[9] = (theta_set >> 16) & 0xFF;
91 buf[10] = (theta_set >> 24) & 0xFF;
92 buf[11] = k_pos & 0xFF;
93 buf[12] = (k_pos >> 8) & 0xFF;
94 buf[13] = k_spd & 0xFF;
95 buf[14] = (k_spd >> 8) & 0xFF;
96 uint16_t crc = crc16_ccitt(buf.data(), 15);
98 buf[16] = (crc >> 8) & 0xFF;
102 static inline std::optional<UnitreeGoFeedback>
103 to_unitree_go_feedback(
const std::array<uint8_t, 16> &buf) {
104 if (buf[0] != 0xFD || buf[1] != 0xEE) {
107 uint16_t crc = (buf[15] << 8) | buf[14];
108 if (crc != crc16_ccitt(buf.data(), 14)) {
112 UnitreeGoFeedback feedback;
113 feedback.id = buf[2] & 0x0F;
114 feedback.mode =
static_cast<UnitreeGoMode>((buf[2] >> 4) & 0x07);
115 feedback.torque =
static_cast<int16_t
>((buf[4] << 8) | buf[3]) / 256.0f;
116 feedback.radps =
static_cast<int16_t
>((buf[6] << 8) | buf[5]) / 256.0f *
117 2.0f * std::numbers::pi;
118 feedback.rad =
static_cast<int32_t
>((buf[10] << 24) | (buf[9] << 16) |
119 (buf[8] << 8) | buf[7]) /
120 32768.0f * 2.0f * std::numbers::pi;
121 feedback.temp = buf[11];
123 feedback.force = (buf[13] & 0x7F) | ((buf[12] >> 3) & 0x1F);
127 static inline uint16_t crc16_ccitt(
const uint8_t *data,
size_t size) {
129 for (
size_t i = 0; i < size; ++i) {
131 for (uint8_t j = 0; j < 8; ++j) {
132 crc = crc & 1 ? (crc >> 1) ^ 0x8408 : crc >> 1;