#include #include #include #include #include #include #include "gamepad.hpp" // DDS #include #include // IDL #include #include #include #include static const std::string HG_CMD_TOPIC = "rt/lowcmd"; static const std::string HG_IMU_TORSO = "rt/secondary_imu"; static const std::string HG_STATE_TOPIC = "rt/lowstate"; using namespace unitree::common; using namespace unitree::robot; using namespace unitree_hg::msg::dds_; template class DataBuffer { public: void SetData(const T &newData) { std::unique_lock lock(mutex); data = std::make_shared(newData); } std::shared_ptr GetData() { std::shared_lock lock(mutex); return data ? data : nullptr; } void Clear() { std::unique_lock lock(mutex); data = nullptr; } private: std::shared_ptr data; std::shared_mutex mutex; }; const int G1D_NUM_MOTOR = 29; // IMU状态结构体 struct ImuState { std::array rpy = {}; std::array omega = {}; }; // 电机控制指令结构体 struct MotorCommand { std::array q_target = {}; std::array dq_target = {}; std::array kp = {}; std::array kd = {}; std::array tau_ff = {}; }; // 电机状态结构体 struct MotorState { std::array q = {}; std::array dq = {}; }; // Stiffness for all G1D Joints std::array Kp{ 0, 0, 0, 0, 0, 0, // empty 0, 0, 0, 0, 0, 0, // empty 60, 0, 40, // waist 40, 40, 40, 40, 40, 40, 40, // arms 40, 40, 40, 40, 40, 40, 40 // arms }; // Damping for all G1D Joints std::array Kd{ 0, 0, 0, 0, 0, 0, // empty 0, 0, 0, 0, 0, 0, // empty 1, 0, 1, // waist 1, 1, 1, 1, 1, 1, 1, // arms 1, 1, 1, 1, 1, 1, 1 // arms }; uint8_t mode_machine_; Gamepad gamepad_; REMOTE_DATA_RX rx_; DataBuffer motor_state_buffer_; DataBuffer motor_command_buffer_; DataBuffer imu_state_buffer_; ThreadPtr command_writer_ptr_, control_thread_ptr_; LowState_ g1d_low_state; IMUState_ Torso_IMU; bool A_PRESSED = false; bool IMU_Get = false; enum G1DJointIndex { LeftHipPitch = 0, // NOTE INVALID for g1d LeftHipRoll = 1, // NOTE INVALID for g1d LeftHipYaw = 2, // NOTE INVALID for g1d LeftKnee = 3, // NOTE INVALID for g1d LeftAnklePitch = 4, // NOTE INVALID for g1d LeftAnkleB = 4, // NOTE INVALID for g1d LeftAnkleRoll = 5, // NOTE INVALID for g1d LeftAnkleA = 5, // NOTE INVALID for g1d RightHipPitch = 6, // NOTE INVALID for g1d RightHipRoll = 7, // NOTE INVALID for g1d RightHipYaw = 8, // NOTE INVALID for g1d RightKnee = 9, // NOTE INVALID for g1d RightAnklePitch = 10, // NOTE INVALID for g1d RightAnkleB = 10, // NOTE INVALID for g1d RightAnkleRoll = 11, // NOTE INVALID for g1d RightAnkleA = 11, // NOTE INVALID for g1d WaistYaw = 12, WaistRoll = 13, // NOTE INVALID for g1d WaistA = 13, // NOTE INVALID for g1d WaistPitch = 14, WaistB = 14, // NOTE INVALID for g1d LeftShoulderPitch = 15, LeftShoulderRoll = 16, LeftShoulderYaw = 17, LeftElbow = 18, LeftWristRoll = 19, LeftWristPitch = 20, LeftWristYaw = 21, RightShoulderPitch = 22, RightShoulderRoll = 23, RightShoulderYaw = 24, RightElbow = 25, RightWristRoll = 26, RightWristPitch = 27, RightWristYaw = 28 }; // CRC校验值计算 inline uint32_t Crc32Core(uint32_t *ptr, uint32_t len) { uint32_t xbit = 0; uint32_t data = 0; uint32_t CRC32 = 0xFFFFFFFF; const uint32_t dwPolynomial = 0x04c11db7; for (uint32_t i = 0; i < len; i++) { xbit = 1 << 31; data = ptr[i]; for (uint32_t bits = 0; bits < 32; bits++) { if (CRC32 & 0x80000000) { CRC32 <<= 1; CRC32 ^= dwPolynomial; } else CRC32 <<= 1; if (data & xbit) CRC32 ^= dwPolynomial; xbit >>= 1; } } return CRC32; }; // 躯干IMU消息回调函数 void imuTorsoHandler(const void *message) { IMUState_ imu_torso = *(const IMUState_ *)message; Torso_IMU = imu_torso; } // 底层状态消息回调函数 void LowStateHandler(const void *message) { LowState_ low_state = *(const LowState_ *)message; g1d_low_state = low_state; if (low_state.crc() != Crc32Core((uint32_t *)&low_state, (sizeof(LowState_) >> 2) - 1)) { std::cout << "[ERROR] CRC Error" << std::endl; return; } // 获取关节电机数据 MotorState ms_tmp; for (int i = 0; i < G1D_NUM_MOTOR; ++i) { ms_tmp.q.at(i) = low_state.motor_state()[i].q(); ms_tmp.dq.at(i) = low_state.motor_state()[i].dq(); if (low_state.motor_state()[i].motorstate() && i <= RightAnkleRoll) std::cout << "[ERROR] motor " << i << " with code " << low_state.motor_state()[i].motorstate() << "\n"; } motor_state_buffer_.SetData(ms_tmp); // 获取IMU数据 ImuState imu_tmp; imu_tmp.omega = low_state.imu_state().gyroscope(); imu_tmp.rpy = low_state.imu_state().rpy(); imu_state_buffer_.SetData(imu_tmp); IMU_Get = true; // 更新遥控器状态 memcpy(rx_.buff, &low_state.wireless_remote()[0], 40); gamepad_.update(rx_.RF_RX); if(gamepad_.A.on_press) A_PRESSED = true; // 更新机型编号 mode_machine_ = low_state.mode_machine(); } int main(int argc, char const *argv[]) { if (argc < 2) { std::cout << "Usage: g1d_arm_example network_interface" << std::endl; exit(0); } std::string networkInterface = argv[1]; ChannelFactory::Instance()->Init(0, networkInterface); // Publisher ChannelPublisherPtr lowcmd_publisher(new ChannelPublisher(HG_CMD_TOPIC)); lowcmd_publisher->InitChannel(); // Subscriber ChannelSubscriberPtr lowstate_subscriber(new ChannelSubscriber(HG_STATE_TOPIC)); lowstate_subscriber->InitChannel(LowStateHandler, 1); ChannelSubscriberPtr imu_subscriber(new ChannelSubscriber(HG_IMU_TORSO)); imu_subscriber->InitChannel(imuTorsoHandler, 1); // 等待接收到第一帧IMU数据,打印躯干IMU状态信息 while(!IMU_Get){ std::this_thread::sleep_for(std::chrono::milliseconds(10)); } std::cout << "Torso IMU State: " << std::endl << "RPY = " << Torso_IMU.rpy()[0] << ", " << Torso_IMU.rpy()[1] << ", " << Torso_IMU.rpy()[2] << std::endl << "Gyro = " << Torso_IMU.gyroscope()[0] << ", " << Torso_IMU.gyroscope()[1] << ", " << Torso_IMU.gyroscope()[2] << std::endl; // 等待遥控器A键按下 std::cout << "Press button A on the remote control to continue!" << std::endl; while(true){ std::this_thread::sleep_for(std::chrono::milliseconds(10)); if(A_PRESSED){ A_PRESSED = false; break; } } std::cout << "A Pressed!" << std::endl; // 手臂摆动 LowCmd_ dds_low_command; dds_low_command.mode_pr() = static_cast(0); //构造底层控制指令 dds_low_command.mode_machine() = mode_machine_; for (size_t i = 0; i < G1D_NUM_MOTOR; i++) { dds_low_command.motor_cmd().at(i).mode() = 1; // 1:Enable, 0:Disable dds_low_command.motor_cmd().at(i).tau() = 0; dds_low_command.motor_cmd().at(i).q() = motor_state_buffer_.GetData() -> q.at(i); dds_low_command.motor_cmd().at(i).dq() = 0; dds_low_command.motor_cmd().at(i).kp() = Kp.at(i); dds_low_command.motor_cmd().at(i).kd() = Kd.at(i); } double control_dt = 0.002; double max_P = M_PI * 30.0 / 180.0; double t = 0.0; std::cout << "Press button A on the remote control to exit the program!" << std::endl; while(true){ double L_Shoulder_des = max_P * std::sin(2.0 * M_PI * t); double R_Shoulder_des = -max_P * std::sin(2.0 * M_PI * t); dds_low_command.motor_cmd().at(LeftShoulderPitch).q() = L_Shoulder_des; dds_low_command.motor_cmd().at(RightShoulderPitch).q() = R_Shoulder_des; dds_low_command.crc() = Crc32Core((uint32_t *)&dds_low_command, (sizeof(dds_low_command) >> 2) - 1); lowcmd_publisher -> Write(dds_low_command); //发布底层控制指令 t += control_dt; // 按下遥控器A键或键盘Ctrl+C退出程序 if(A_PRESSED){ A_PRESSED = false; break; } std::this_thread::sleep_for(std::chrono::milliseconds(5)); } return 0; }