/* * @file virtual_chassis.c * @brief 虚拟底盘设备驱动实现 - 控制端 * @details 作为控制端,发送控制命令到底盘,接收底盘反馈数据 */ /* Includes ----------------------------------------------------------------- */ #include "device/virtual_chassis.h" #include "bsp/can.h" #include "bsp/time.h" #include #include /* Private typedef ---------------------------------------------------------- */ /* Private define ----------------------------------------------------------- */ /* Private macro ------------------------------------------------------------ */ /* Private variables -------------------------------------------------------- */ /* Private function prototypes ---------------------------------------------- */ /** * @brief 解析关节电机反馈数据 (ID: 124-127) * @param chassis 虚拟底盘结构体 * @param id CAN ID * @param data 数据包 * @return 解析结果 */ static int8_t Virtual_Chassis_DecodeJointMotor(Virtual_Chassis_t *chassis, uint16_t id, uint8_t *data) { if (chassis == NULL || data == NULL) { return DEVICE_ERR_NULL; } int motor_idx = id - chassis->param.motors.joint_feedback_base_id; if (motor_idx < 0 || motor_idx >= 4) { return DEVICE_ERR; } // 解析关节电机反馈数据:转矩电流(2字节) + 位置(3字节) + 速度(3字节) // 1. 解析转矩电流 - 前2字节,16位有符号整数 (精度0.01 Nm) int16_t torque_int; memcpy(&torque_int, &data[0], sizeof(int16_t)); chassis->data.joint[motor_idx].torque_current = (float)torque_int / 100.0f; // 2. 解析位置 - 第3-5字节,24位有符号整数 (精度0.0001 rad) int32_t angle_int = 0; angle_int |= ((int32_t)data[2]) << 16; angle_int |= ((int32_t)data[3]) << 8; angle_int |= ((int32_t)data[4]); // 符号扩展(24位转32位) if (angle_int & 0x800000) { angle_int |= 0xFF000000; } chassis->data.joint[motor_idx].rotor_abs_angle = (float)angle_int / 10000.0f; // 3. 解析速度 - 第6-8字节,24位有符号整数 (精度0.001 rad/s) int32_t velocity_int = 0; velocity_int |= ((int32_t)data[5]) << 16; velocity_int |= ((int32_t)data[6]) << 8; velocity_int |= ((int32_t)data[7]); // 符号扩展(24位转32位) if (velocity_int & 0x800000) { velocity_int |= 0xFF000000; } chassis->data.joint[motor_idx].rotor_speed = (float)velocity_int / 1000.0f; chassis->data.joint[motor_idx].temp = 0.0f; return DEVICE_OK; } /** * @brief 解析轮子电机反馈数据 (ID: 130-131) * @param chassis 虚拟底盘结构体 * @param id CAN ID * @param data 数据包 * @return 解析结果 */ static int8_t Virtual_Chassis_DecodeWheelMotor(Virtual_Chassis_t *chassis, uint16_t id, uint8_t *data) { if (chassis == NULL || data == NULL) { return DEVICE_ERR_NULL; } int wheel_idx; if (id == chassis->param.motors.wheel_left_feedback_id) { wheel_idx = 0; // 左轮 } else if (id == chassis->param.motors.wheel_right_feedback_id) { wheel_idx = 1; // 右轮 } else { return DEVICE_ERR; } // 解析轮子电机反馈数据:角度(2字节) + 速度(2字节) + 力矩电流(2字节) + 编码器(2字节) // 角度 - 精度0.01度,需转换为弧度 int16_t angle_int; angle_int = (data[0] << 8) | data[1]; chassis->data.wheel[wheel_idx].rotor_abs_angle = (float)angle_int / 100.0f * M_PI / 180.0f; // 速度 - 精度1dps,直接赋值 int16_t speed_int; speed_int = (data[2] << 8) | data[3]; chassis->data.wheel[wheel_idx].rotor_speed = (float)speed_int; // 力矩电流 int16_t current_int; current_int = (data[4] << 8) | data[5]; chassis->data.wheel[wheel_idx].torque_current = (float)current_int; // 编码器值(暂不使用) chassis->data.wheel[wheel_idx].temp = 0.0f; return DEVICE_OK; } /** * @brief 解析IMU数据 * @param chassis 虚拟底盘结构体 * @param id CAN ID * @param data 数据包 * @return 解析结果 */ static int8_t Virtual_Chassis_DecodeIMU(Virtual_Chassis_t *chassis, uint16_t id, uint8_t *data) { if (chassis == NULL || data == NULL) { return DEVICE_ERR_NULL; } if (id == chassis->param.imu.accl_id) { // 加速度计数据 - x/y轴24位,z轴16位 // x: 24位有符号整数 (字节0-2) - 精度1/1000000 int32_t x_int = 0; x_int |= ((int32_t)data[0]) << 16; x_int |= ((int32_t)data[1]) << 8; x_int |= ((int32_t)data[2]); // 符号扩展(24位转32位) if (x_int & 0x800000) { x_int |= 0xFF000000; } chassis->data.imu.accl.x = (float)x_int / 1000000.0f; // y: 24位有符号整数 (字节3-5) - 精度1/1000000 int32_t y_int = 0; y_int |= ((int32_t)data[3]) << 16; y_int |= ((int32_t)data[4]) << 8; y_int |= ((int32_t)data[5]); // 符号扩展(24位转32位) if (y_int & 0x800000) { y_int |= 0xFF000000; } chassis->data.imu.accl.y = (float)y_int / 1000000.0f; // z: 16位有符号整数 (字节6-7) - 精度1/10000 int16_t z_int; memcpy(&z_int, &data[6], sizeof(int16_t)); chassis->data.imu.accl.z = (float)z_int / 10000.0f; } else if (id == chassis->param.imu.gyro_id) { // 陀螺仪数据 - x/y轴24位,z轴16位 // x: 24位有符号整数 (字节0-2) - 精度0.001°/s int32_t x_int = 0; x_int |= ((int32_t)data[0]) << 16; x_int |= ((int32_t)data[1]) << 8; x_int |= ((int32_t)data[2]); // 符号扩展(24位转32位) if (x_int & 0x800000) { x_int |= 0xFF000000; } chassis->data.imu.gyro.x = ((float)x_int / 1000.0f) * M_PI / 180.0f; // °/s -> rad/s // y: 24位有符号整数 (字节3-5) - 精度0.001°/s int32_t y_int = 0; y_int |= ((int32_t)data[3]) << 16; y_int |= ((int32_t)data[4]) << 8; y_int |= ((int32_t)data[5]); // 符号扩展(24位转32位) if (y_int & 0x800000) { y_int |= 0xFF000000; } chassis->data.imu.gyro.y = ((float)y_int / 1000.0f) * M_PI / 180.0f; // °/s -> rad/s // z: 16位有符号整数 (字节6-7) - 精度0.01°/s int16_t z_int; memcpy(&z_int, &data[6], sizeof(int16_t)); chassis->data.imu.gyro.z = ((float)z_int / 100.0f) * M_PI / 180.0f; // °/s -> rad/s } else if (id == chassis->param.imu.euler_id) { // 欧拉角数据 - yaw/pitch轴24位,roll轴16位 // yaw: 24位有符号整数 (字节0-2) - 精度0.0001° int32_t yaw_int = 0; yaw_int |= ((int32_t)data[0]) << 16; yaw_int |= ((int32_t)data[1]) << 8; yaw_int |= ((int32_t)data[2]); // 符号扩展(24位转32位) if (yaw_int & 0x800000) { yaw_int |= 0xFF000000; } chassis->data.imu.euler.yaw = ((float)yaw_int / 10000.0f) * M_PI / 180.0f; // ° -> rad // pitch: 24位有符号整数 (字节3-5) - 精度0.0001° int32_t pit_int = 0; pit_int |= ((int32_t)data[3]) << 16; pit_int |= ((int32_t)data[4]) << 8; pit_int |= ((int32_t)data[5]); // 符号扩展(24位转32位) if (pit_int & 0x800000) { pit_int |= 0xFF000000; } chassis->data.imu.euler.pit = ((float)pit_int / 10000.0f) * M_PI / 180.0f; // ° -> rad // roll: 16位有符号整数 (字节6-7) - 精度0.001° int16_t rol_int; memcpy(&rol_int, &data[6], sizeof(int16_t)); chassis->data.imu.euler.rol = ((float)rol_int / 1000.0f) * M_PI / 180.0f; // ° -> rad } else if (id == chassis->param.imu.quat_id) { // 四元数数据 - q0/q1/q2/q3 各2字节,精度1/32767 int16_t q0, q1, q2, q3; memcpy(&q0, &data[0], 2); memcpy(&q1, &data[2], 2); memcpy(&q2, &data[4], 2); memcpy(&q3, &data[6], 2); chassis->data.imu.quat.q0 = q0 / 32767.0f; chassis->data.imu.quat.q1 = q1 / 32767.0f; chassis->data.imu.quat.q2 = q2 / 32767.0f; chassis->data.imu.quat.q3 = q3 / 32767.0f; } else { return DEVICE_ERR; } return DEVICE_OK; } /* Exported functions ------------------------------------------------------- */ /** * @brief 初始化虚拟底盘设备 */ int8_t Virtual_Chassis_Init(Virtual_Chassis_t *chassis, Virtual_Chassis_Param_t *param) { if (chassis == NULL || param == NULL) { return DEVICE_ERR_NULL; } // 复制参数配置 chassis->param = *param; // 初始化设备头部 chassis->header.online = false; chassis->header.last_online_time = 0; // 初始化数据 memset(&chassis->data, 0, sizeof(Virtual_Chassis_Feedback_t)); memset(&chassis->output, 0, sizeof(Virtual_Chassis_Output_t)); BSP_CAN_Init(); // 注册关节电机反馈ID (124-127) for (int i = 0; i < 4; i++) { BSP_CAN_RegisterId(chassis->param.motors.can, chassis->param.motors.joint_feedback_base_id + i, 3); } // 注册轮子电机反馈ID (130-131) BSP_CAN_RegisterId(chassis->param.motors.can, chassis->param.motors.wheel_left_feedback_id, 3); BSP_CAN_RegisterId(chassis->param.motors.can, chassis->param.motors.wheel_right_feedback_id, 3); // 注册IMU数据ID (769-772 / 0x301-0x304) BSP_CAN_RegisterId(chassis->param.imu.can, chassis->param.imu.accl_id, 3); BSP_CAN_RegisterId(chassis->param.imu.can, chassis->param.imu.gyro_id, 3); BSP_CAN_RegisterId(chassis->param.imu.can, chassis->param.imu.euler_id, 3); BSP_CAN_RegisterId(chassis->param.imu.can, chassis->param.imu.quat_id, 3); // 设置设备在线状态 chassis->header.online = true; chassis->header.last_online_time = BSP_TIME_Get_us(); return DEVICE_OK; } /** * @brief 更新虚拟底盘数据(接收底盘反馈数据) */ int8_t Virtual_Chassis_Update(Virtual_Chassis_t *chassis) { if (chassis == NULL) { return DEVICE_ERR_NULL; } BSP_CAN_Message_t msg; // 接收IMU数据 if (BSP_CAN_GetMessage(chassis->param.imu.can, chassis->param.imu.accl_id, &msg, BSP_CAN_TIMEOUT_IMMEDIATE) == BSP_OK) { Virtual_Chassis_DecodeIMU(chassis, chassis->param.imu.accl_id, msg.data); } if (BSP_CAN_GetMessage(chassis->param.imu.can, chassis->param.imu.gyro_id, &msg, BSP_CAN_TIMEOUT_IMMEDIATE) == BSP_OK) { Virtual_Chassis_DecodeIMU(chassis, chassis->param.imu.gyro_id, msg.data); } if (BSP_CAN_GetMessage(chassis->param.imu.can, chassis->param.imu.euler_id, &msg, BSP_CAN_TIMEOUT_IMMEDIATE) == BSP_OK) { Virtual_Chassis_DecodeIMU(chassis, chassis->param.imu.euler_id, msg.data); } if (BSP_CAN_GetMessage(chassis->param.imu.can, chassis->param.imu.quat_id, &msg, BSP_CAN_TIMEOUT_IMMEDIATE) == BSP_OK) { Virtual_Chassis_DecodeIMU(chassis, chassis->param.imu.quat_id, msg.data); } // 接收关节电机反馈数据 (124-127) for (int i = 0; i < 4; i++) { uint16_t joint_id = chassis->param.motors.joint_feedback_base_id + i; if (BSP_CAN_GetMessage(chassis->param.motors.can, joint_id, &msg, BSP_CAN_TIMEOUT_IMMEDIATE) == BSP_OK) { Virtual_Chassis_DecodeJointMotor(chassis, joint_id, msg.data); } } // 接收轮子电机反馈数据 (130-131) if (BSP_CAN_GetMessage(chassis->param.motors.can, chassis->param.motors.wheel_left_feedback_id, &msg, BSP_CAN_TIMEOUT_IMMEDIATE) == BSP_OK) { Virtual_Chassis_DecodeWheelMotor(chassis, chassis->param.motors.wheel_left_feedback_id, msg.data); } if (BSP_CAN_GetMessage(chassis->param.motors.can, chassis->param.motors.wheel_right_feedback_id, &msg, BSP_CAN_TIMEOUT_IMMEDIATE) == BSP_OK) { Virtual_Chassis_DecodeWheelMotor(chassis, chassis->param.motors.wheel_right_feedback_id, msg.data); } return DEVICE_OK; } /** * @brief 发送电机使能命令 */ int8_t Virtual_Chassis_Enable(Virtual_Chassis_t *chassis) { if (chassis == NULL) { return DEVICE_ERR_NULL; } BSP_CAN_StdDataFrame_t enable_frame = { .id = chassis->param.motors.enable_id, .dlc = 0, .data = {0} }; chassis->output.enable_joints = true; if (BSP_CAN_TransmitStdDataFrame(chassis->param.motors.can, &enable_frame) == BSP_OK) { return DEVICE_OK; } return DEVICE_ERR; } /** * @brief 发送关节电机力矩控制命令 */ int8_t Virtual_Chassis_SendJointTorque(Virtual_Chassis_t *chassis, float torques[4]) { if (chassis == NULL || torques == NULL) { return DEVICE_ERR_NULL; } BSP_CAN_StdDataFrame_t torque_frame = { .id = chassis->param.motors.joint_cmd_id, .dlc = 8, .data = {0} }; // 8字节数据分别是4个电机的力矩 (每个电机2字节,有符号整数,精度0.01 Nm) for (int i = 0; i < 4; i++) { int16_t torque_raw = (int16_t)(torques[i] * 100.0f); memcpy(&torque_frame.data[i * 2], &torque_raw, sizeof(int16_t)); chassis->output.joint_torque[i] = torques[i]; } return BSP_CAN_TransmitStdDataFrame(chassis->param.motors.can, &torque_frame) == BSP_OK ? DEVICE_OK : DEVICE_ERR; } /** * @brief 发送轮子电机控制命令 */ int8_t Virtual_Chassis_SendWheelCommand(Virtual_Chassis_t *chassis, float left_out, float right_out) { if (chassis == NULL) { return DEVICE_ERR_NULL; } int16_t torque_control = (int16_t)(left_out * 2048); // 构建CAN帧 BSP_CAN_StdDataFrame_t tx_frame; tx_frame.id = chassis->param.motors.wheel_left_id; tx_frame.dlc = 8; tx_frame.data[0] = 0xA1; tx_frame.data[1] = 0x00; tx_frame.data[2] = 0x00; tx_frame.data[3] = 0x00; tx_frame.data[4] = (uint8_t)(torque_control & 0xFF); tx_frame.data[5] = (uint8_t)((torque_control >> 8) & 0xFF); tx_frame.data[6] = 0x00; tx_frame.data[7] = 0x00; if (BSP_CAN_TransmitStdDataFrame(chassis->param.motors.can, &tx_frame) != BSP_OK) { return DEVICE_ERR; } torque_control = (int16_t)(right_out * 2048); // 构建CAN帧 tx_frame.id = chassis->param.motors.wheel_right_id; tx_frame.dlc = 8; tx_frame.data[0] = 0xA1; tx_frame.data[1] = 0x00; tx_frame.data[2] = 0x00; tx_frame.data[3] = 0x00; tx_frame.data[4] = (uint8_t)(torque_control & 0xFF); tx_frame.data[5] = (uint8_t)((torque_control >> 8) & 0xFF); tx_frame.data[6] = 0x00; tx_frame.data[7] = 0x00; if (BSP_CAN_TransmitStdDataFrame(chassis->param.motors.can, &tx_frame) != BSP_OK) { return DEVICE_ERR; } } /* Private functions -------------------------------------------------------- */