有反馈了

This commit is contained in:
Robofish 2025-10-05 12:04:46 +08:00
parent 722ea07411
commit 3b1ef030c2
6 changed files with 472 additions and 98 deletions

View File

@ -9,23 +9,37 @@
#include "bsp/can.h"
#include "bsp/time.h"
#include <string.h>
#include <math.h>
/* Private typedef ---------------------------------------------------------- */
/* Private define ----------------------------------------------------------- */
/* Private macro ------------------------------------------------------------ */
/* Private variables -------------------------------------------------------- */
/* Private function prototypes ---------------------------------------------- */
static int8_t Virtual_Chassis_DecodeMotor(Virtual_Chassis_t *chassis, uint8_t id, uint8_t *data) {
/**
* @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[id-chassis->param.motors.feedback_id].torque_current = (float)torque_int / 100.0f;
chassis->data.joint[motor_idx].torque_current = (float)torque_int / 100.0f;
// 2. 解析位置 - 第3-5字节24位有符号整数 (精度0.0001 rad)
int32_t angle_int = 0;
@ -37,7 +51,7 @@ static int8_t Virtual_Chassis_DecodeMotor(Virtual_Chassis_t *chassis, uint8_t id
if (angle_int & 0x800000) {
angle_int |= 0xFF000000;
}
chassis->data.joint[id-chassis->param.motors.feedback_id].rotor_abs_angle = (float)angle_int / 10000.0f;
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;
@ -49,63 +63,110 @@ static int8_t Virtual_Chassis_DecodeMotor(Virtual_Chassis_t *chassis, uint8_t id
if (velocity_int & 0x800000) {
velocity_int |= 0xFF000000;
}
chassis->data.joint[id-chassis->param.motors.feedback_id].rotor_speed = (float)velocity_int / 1000.0f;
chassis->data.joint[motor_idx].rotor_speed = (float)velocity_int / 1000.0f;
chassis->data.joint[id-chassis->param.motors.feedback_id].temp = 0.0f;
chassis->data.joint[motor_idx].temp = 0.0f;
return DEVICE_OK;
}
static int8_t Virtual_Chassis_DecodeIMU(Virtual_Chassis_t *chassis, uint8_t id, uint8_t *data) {
/**
* @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;
}
switch (id) {
case 150: { // 加速度计数据 - x/y/z 各2字节精度0.01g
int16_t x, y, z;
memcpy(&x, &data[0], 2);
memcpy(&y, &data[2], 2);
memcpy(&z, &data[4], 2);
chassis->data.imu.accl.x = x / 100.0f;
chassis->data.imu.accl.y = y / 100.0f;
chassis->data.imu.accl.z = z / 100.0f;
break;
}
case 151: { // 陀螺仪数据 - x/y/z 各2字节精度0.01°/s需转回弧度/s
int16_t x, y, z;
memcpy(&x, &data[0], 2);
memcpy(&y, &data[2], 2);
memcpy(&z, &data[4], 2);
chassis->data.imu.gyro.x = (x / 100.0f) * 0.0174533f; // °/s -> rad/s
chassis->data.imu.gyro.y = (y / 100.0f) * 0.0174533f;
chassis->data.imu.gyro.z = (z / 100.0f) * 0.0174533f;
break;
}
case 152: { // 欧拉角数据 - yaw/pitch/roll 各2字节精度0.01°,需转回弧度
int16_t yaw, pit, rol;
memcpy(&yaw, &data[0], 2);
memcpy(&pit, &data[2], 2);
memcpy(&rol, &data[4], 2);
chassis->data.imu.euler.yaw = (yaw / 100.0f) * 0.0174533f; // ° -> rad
chassis->data.imu.euler.pit = (pit / 100.0f) * 0.0174533f;
chassis->data.imu.euler.rol = (rol / 100.0f) * 0.0174533f;
break;
}
case 153: { // 四元数数据 - q0/q1/q2/q3 各2字节精度0.0001
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 / 10000.0f;
chassis->data.imu.quat.q1 = q1 / 10000.0f;
chassis->data.imu.quat.q2 = q2 / 10000.0f;
chassis->data.imu.quat.q3 = q3 / 10000.0f;
break;
}
default:
return DEVICE_ERR;
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/z 各2字节精度0.01g
int16_t x, y, z;
memcpy(&x, &data[0], 2);
memcpy(&y, &data[2], 2);
memcpy(&z, &data[4], 2);
chassis->data.imu.accl.x = x / 100.0f;
chassis->data.imu.accl.y = y / 100.0f;
chassis->data.imu.accl.z = z / 100.0f;
}
else if (id == chassis->param.imu.gyro_id) { // 陀螺仪数据 - x/y/z 各2字节精度0.01°/s
int16_t x, y, z;
memcpy(&x, &data[0], 2);
memcpy(&y, &data[2], 2);
memcpy(&z, &data[4], 2);
// 注意底盘发送的是精度0.01°/s而不是0.1°/s所以除以100而不是10
chassis->data.imu.gyro.x = (x / 100.0f) * M_PI / 180.0f; // °/s -> rad/s
chassis->data.imu.gyro.y = (y / 100.0f) * M_PI / 180.0f;
chassis->data.imu.gyro.z = (z / 100.0f) * M_PI / 180.0f;
}
else if (id == chassis->param.imu.euler_id) { // 欧拉角数据 - yaw/pitch/roll 各2字节精度0.01°
int16_t yaw, pit, rol;
memcpy(&yaw, &data[0], 2);
memcpy(&pit, &data[2], 2);
memcpy(&rol, &data[4], 2);
chassis->data.imu.euler.yaw = (yaw / 100.0f) * M_PI / 180.0f; // ° -> rad
chassis->data.imu.euler.pit = (pit / 100.0f) * M_PI / 180.0f;
chassis->data.imu.euler.rol = (rol / 100.0f) * M_PI / 180.0f;
}
else if (id == chassis->param.imu.quat_id) { // 四元数数据 - q0/q1/q2/q3 各2字节精度1/32000
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 / 32000.0f;
chassis->data.imu.quat.q1 = q1 / 32000.0f;
chassis->data.imu.quat.q2 = q2 / 32000.0f;
chassis->data.imu.quat.q3 = q3 / 32000.0f;
}
else {
return DEVICE_ERR;
}
return DEVICE_OK;
@ -134,11 +195,21 @@ int8_t Virtual_Chassis_Init(Virtual_Chassis_t *chassis, Virtual_Chassis_Param_t
BSP_CAN_Init();
// 注册关节电机反馈ID (124-127)
for (int i = 0; i < 4; i++) {
BSP_CAN_RegisterId(chassis->param.motors.can, 124 + i, 3); // 电机反馈ID
BSP_CAN_RegisterId(chassis->param.imu.can, 150 + i, 3);
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();
@ -157,24 +228,35 @@ int8_t Virtual_Chassis_Update(Virtual_Chassis_t *chassis) {
BSP_CAN_Message_t msg;
for (int i = 0; i < 4; i++){
if(BSP_CAN_GetMessage(chassis->param.imu.can, 150 + i, &msg, BSP_CAN_TIMEOUT_IMMEDIATE) != BSP_OK){
continue;
} else {
Virtual_Chassis_DecodeIMU(chassis, 150 + i, msg.data);
// 接收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);
}
}
for (int i = 0; i < 4; i++){
if (BSP_CAN_GetMessage(chassis->param.motors.can, 124 + i, &msg, BSP_CAN_TIMEOUT_IMMEDIATE) != BSP_OK){
continue;
} else {
// 解析电机反馈数据
Virtual_Chassis_DecodeMotor(chassis, 124 + i, 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;
}
@ -189,9 +271,13 @@ int8_t Virtual_Chassis_Enable(Virtual_Chassis_t *chassis) {
}
BSP_CAN_StdDataFrame_t enable_frame = {
.id = chassis->param.motors.Enable_id,
.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;
}
@ -200,15 +286,15 @@ int8_t Virtual_Chassis_Enable(Virtual_Chassis_t *chassis) {
}
/**
* @brief
* @brief
*/
int8_t Virtual_Chassis_SendTorqueCommand(Virtual_Chassis_t *chassis, float torques[4]) {
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.MIT_id,
.id = chassis->param.motors.joint_cmd_id,
.dlc = 8,
.data = {0}
};
@ -223,5 +309,46 @@ int8_t Virtual_Chassis_SendTorqueCommand(Virtual_Chassis_t *chassis, float torqu
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, uint8_t left_cmd[8], uint8_t right_cmd[8]) {
if (chassis == NULL || left_cmd == NULL || right_cmd == NULL) {
return DEVICE_ERR_NULL;
}
// 发送左轮控制命令
BSP_CAN_StdDataFrame_t left_frame = {
.id = chassis->param.motors.wheel_left_id,
.dlc = 8,
};
memcpy(left_frame.data, left_cmd, 8);
memcpy(chassis->output.wheel_left_cmd, left_cmd, 8);
// 发送右轮控制命令
BSP_CAN_StdDataFrame_t right_frame = {
.id = chassis->param.motors.wheel_right_id,
.dlc = 8,
};
memcpy(right_frame.data, right_cmd, 8);
memcpy(chassis->output.wheel_right_cmd, right_cmd, 8);
int8_t result1 = BSP_CAN_TransmitStdDataFrame(chassis->param.motors.can, &left_frame);
int8_t result2 = BSP_CAN_TransmitStdDataFrame(chassis->param.motors.can, &right_frame);
return (result1 == BSP_OK && result2 == BSP_OK) ? DEVICE_OK : DEVICE_ERR;
}
/**
* @brief 线
*/
bool Virtual_Chassis_IsOnline(Virtual_Chassis_t *chassis) {
if (chassis == NULL) {
return false;
}
return chassis->header.online;
}
/* Private functions -------------------------------------------------------- */

View File

@ -16,37 +16,46 @@ extern "C" {
/* Exported macro ----------------------------------------------------------- */
/* Exported types ----------------------------------------------------------- */
/* 电机反馈数据结构体 */
/* 虚拟底盘反馈数据结构体 */
typedef struct {
MOTOR_Feedback_t joint[4]; // 4个电机反馈数据
MOTOR_Feedback_t joint[4]; // 4个关节电机反馈数据
MOTOR_Feedback_t wheel[2]; // 2个轮子电机反馈数据
struct {
DEVICE_Header_t header; // 设备通用头部
AHRS_Accl_t accl; // 加速度计数据
AHRS_Gyro_t gyro; // 陀螺仪数据
AHRS_Eulr_t euler; // 欧拉角数据
AHRS_Quaternion_t quat; // 四元数数据
DEVICE_Header_t header; // 设备通用头部
AHRS_Accl_t accl; // 加速度计数据
AHRS_Gyro_t gyro; // 陀螺仪数据
AHRS_Eulr_t euler; // 欧拉角数据
AHRS_Quaternion_t quat; // 四元数数据
} imu;
} Virtual_Chassis_Feedback_t;
/* 虚拟底盘输出控制结构体 */
typedef struct {
float joint_torque[4]; // 4个电机目标力矩
float joint_torque[4]; // 4个关节电机目标力矩
uint8_t wheel_left_cmd[8]; // 左轮控制命令数据
uint8_t wheel_right_cmd[8]; // 右轮控制命令数据
bool enable_joints; // 关节使能标志
} Virtual_Chassis_Output_t;
/* 电机CAN参数结构体 */
typedef struct {
BSP_CAN_t can; // 电机所在CAN总线
uint16_t Enable_id; // 电机使能命令CAN ID
uint16_t MIT_id; // 电机力矩控制命令CAN ID
uint16_t feedback_id; // 电机反馈数据CAN ID
uint16_t enable_id; // 电机使能命令CAN ID (121)
uint16_t joint_cmd_id; // 关节力矩控制命令CAN ID (122)
uint16_t wheel_left_id; // 左轮控制命令CAN ID (128)
uint16_t wheel_right_id; // 右轮控制命令CAN ID (129)
uint16_t joint_feedback_base_id; // 关节反馈基础ID (124-127)
uint16_t wheel_left_feedback_id; // 左轮反馈ID (130)
uint16_t wheel_right_feedback_id; // 右轮反馈ID (131)
} Virtual_Chassis_MotorParam_t;
/* IMU参数结构体 */
typedef struct {
BSP_CAN_t can; // 电机所在CAN总线
uint16_t accl_id; // 加速度计数据CAN ID
uint16_t gyro_id; // 陀螺仪数据CAN ID
uint16_t euler_id; // 欧拉角数据CAN ID
uint16_t quat_id; // 四元数数据CAN ID
BSP_CAN_t can; // IMU所在CAN总线
uint16_t accl_id; // 加速度计数据CAN ID (0x301/769)
uint16_t gyro_id; // 陀螺仪数据CAN ID (0x302/770)
uint16_t euler_id; // 欧拉角数据CAN ID (0x303/771)
uint16_t quat_id; // 四元数数据CAN ID (0x304/772)
} Virtual_Chassis_IMUParam_t;
/* 虚拟底盘参数配置结构体 */
@ -88,11 +97,21 @@ int8_t Virtual_Chassis_Update(Virtual_Chassis_t *chassis);
int8_t Virtual_Chassis_Enable(Virtual_Chassis_t *chassis);
/**
* @brief 使
* @brief
* @param chassis
* @param torques 4
* @return DEVICE_OK
*/
int8_t Virtual_Chassis_Enable(Virtual_Chassis_t *chassis);
int8_t Virtual_Chassis_SendJointTorque(Virtual_Chassis_t *chassis, float torques[4]);
/**
* @brief
* @param chassis
* @param left_cmd 8
* @param right_cmd 8
* @return DEVICE_OK
*/
int8_t Virtual_Chassis_SendWheelCommand(Virtual_Chassis_t *chassis, uint8_t left_cmd[8], uint8_t right_cmd[8]);
/**
* @brief 线

View File

@ -187,16 +187,20 @@ Config_RobotParam_t robot_config = {
.virtual_chassis_param = {
.motors = {
.can = BSP_CAN_1,
.Enable_id = 121,
.MIT_id = 0x122,
.feedback_id = 124,
.enable_id = 0x121,
.joint_cmd_id = 0x122,
.joint_feedback_base_id = 124,
.wheel_left_id = 0x128,
.wheel_right_id = 0x129,
.wheel_left_feedback_id = 0x82,
.wheel_right_feedback_id = 0x83,
},
.imu = {
.can = BSP_CAN_1,
.accl_id = 0x66,
.gyro_id = 0x67,
.euler_id = 0x68,
.quat_id = 0x69,
.accl_id = 0x301,
.gyro_id = 0x302,
.euler_id = 0x303,
.quat_id = 0x304,
},
},
};

View File

@ -35,7 +35,7 @@ void Task_Init(void *argument) {
task_runtime.thread.blink = osThreadNew(Task_blink, NULL, &attr_blink);
task_runtime.thread.rc = osThreadNew(Task_rc, NULL, &attr_rc);
task_runtime.thread.atti_esti = osThreadNew(Task_atti_esti, NULL, &attr_atti_esti);
// task_runtime.thread.ctrl_chassis = osThreadNew(Task_ctrl_chassis, NULL, &attr_ctrl_chassis);
task_runtime.thread.ctrl_chassis = osThreadNew(Task_ctrl_chassis, NULL, &attr_ctrl_chassis);
// task_runtime.thread.ctrl_gimbal = osThreadNew(Task_ctrl_gimbal, NULL, &attr_ctrl_gimbal);
// 创建消息队列

95
virtual_chassis_example.c Normal file
View File

@ -0,0 +1,95 @@
/*
* @file virtual_chassis_example.c
* @brief 使
* @details 使
*/
/* Includes ----------------------------------------------------------------- */
#include "device/virtual_chassis.h"
#include "bsp/can.h"
/* Private variables -------------------------------------------------------- */
static Virtual_Chassis_t g_virtual_chassis;
/* Example configuration ---------------------------------------------------- */
/**
* @brief
*/
void Virtual_Chassis_Example_Init(void) {
// 配置虚拟底盘参数
Virtual_Chassis_Param_t chassis_param = {
.motors = {
.can = BSP_CAN_1, // 电机使用CAN1总线
.enable_id = 121, // 使能命令ID
.joint_cmd_id = 122, // 关节力矩控制命令ID
.wheel_left_id = 128, // 左轮控制命令ID
.wheel_right_id = 129, // 右轮控制命令ID
.joint_feedback_base_id = 124, // 关节反馈基础ID (124-127)
.wheel_left_feedback_id = 130, // 左轮反馈ID
.wheel_right_feedback_id = 131, // 右轮反馈ID
},
.imu = {
.can = BSP_CAN_1, // IMU使用CAN1总线
.accl_id = 0x301, // 加速度计数据ID (769)
.gyro_id = 0x302, // 陀螺仪数据ID (770)
.euler_id = 0x303, // 欧拉角数据ID (771)
.quat_id = 0x304, // 四元数数据ID (772)
}
};
// 初始化虚拟底盘
Virtual_Chassis_Init(&g_virtual_chassis, &chassis_param);
}
/**
* @brief
*/
void Virtual_Chassis_Example_Control(void) {
// 1. 更新底盘数据(接收反馈)
Virtual_Chassis_Update(&g_virtual_chassis);
// 2. 使能关节电机
Virtual_Chassis_Enable(&g_virtual_chassis);
// 3. 发送关节电机力矩控制命令
float joint_torques[4] = {0.5f, -0.3f, 0.2f, -0.1f}; // 4个关节的目标力矩 (Nm)
Virtual_Chassis_SendJointTorque(&g_virtual_chassis, joint_torques);
// 4. 发送轮子电机控制命令(示例:速度控制)
uint8_t left_wheel_cmd[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; // 左轮命令
uint8_t right_wheel_cmd[8] = {0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01}; // 右轮命令
Virtual_Chassis_SendWheelCommand(&g_virtual_chassis, left_wheel_cmd, right_wheel_cmd);
}
/**
* @brief
*/
void Virtual_Chassis_Example_ReadData(void) {
// 读取关节电机反馈数据
for (int i = 0; i < 4; i++) {
MOTOR_Feedback_t *joint = &g_virtual_chassis.data.joint[i];
// 使用 joint->torque_current, joint->rotor_abs_angle, joint->rotor_speed
}
// 读取轮子电机反馈数据
for (int i = 0; i < 2; i++) {
MOTOR_Feedback_t *wheel = &g_virtual_chassis.data.wheel[i];
// 使用 wheel->torque_current, wheel->rotor_abs_angle, wheel->rotor_speed
}
// 读取IMU数据
AHRS_Accl_t *accl = &g_virtual_chassis.data.imu.accl;
AHRS_Gyro_t *gyro = &g_virtual_chassis.data.imu.gyro;
AHRS_Eulr_t *euler = &g_virtual_chassis.data.imu.euler;
AHRS_Quaternion_t *quat = &g_virtual_chassis.data.imu.quat;
// 使用IMU数据进行姿态估计或控制
}
/**
* @brief 使
*/
Virtual_Chassis_t* Virtual_Chassis_GetInstance(void) {
return &g_virtual_chassis;
}

129
virtual_chassis_protocol.h Normal file
View File

@ -0,0 +1,129 @@
/*
* @file virtual_chassis_protocol.h
* @brief
* @details CAN通信协议
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/* CAN通信协议定义 --------------------------------------------------------- */
/**
* CAN ID定义
*/
#define VIRTUAL_CHASSIS_CAN_CMD_ENABLE 121 // 关节电机使能命令
#define VIRTUAL_CHASSIS_CAN_CMD_JOINT 122 // 关节力矩控制命令
#define VIRTUAL_CHASSIS_CAN_CMD_WHEEL_LEFT 128 // 左轮控制命令
#define VIRTUAL_CHASSIS_CAN_CMD_WHEEL_RIGHT 129 // 右轮控制命令
/**
* CAN ID定义
*/
#define VIRTUAL_CHASSIS_CAN_FEEDBACK_JOINT_0 124 // 关节电机0反馈
#define VIRTUAL_CHASSIS_CAN_FEEDBACK_JOINT_1 125 // 关节电机1反馈
#define VIRTUAL_CHASSIS_CAN_FEEDBACK_JOINT_2 126 // 关节电机2反馈
#define VIRTUAL_CHASSIS_CAN_FEEDBACK_JOINT_3 127 // 关节电机3反馈
#define VIRTUAL_CHASSIS_CAN_FEEDBACK_WHEEL_LEFT 130 // 左轮电机反馈
#define VIRTUAL_CHASSIS_CAN_FEEDBACK_WHEEL_RIGHT 131 // 右轮电机反馈
/**
* IMU数据CAN ID定义
*/
#define VIRTUAL_CHASSIS_CAN_IMU_ACCL 0x301 // 加速度计数据 (769)
#define VIRTUAL_CHASSIS_CAN_IMU_GYRO 0x302 // 陀螺仪数据 (770)
#define VIRTUAL_CHASSIS_CAN_IMU_EULER 0x303 // 欧拉角数据 (771)
#define VIRTUAL_CHASSIS_CAN_IMU_QUAT 0x304 // 四元数数据 (772)
/* 数据格式定义 ----------------------------------------------------------- */
/**
* (ID: 122)
* 8
* 42
* 0.01 Nm
* -327.68 ~ +327.67 Nm
*/
typedef struct {
int16_t joint_torque[4]; // 关节电机目标力矩 * 100
} Virtual_Chassis_JointCommand_t;
/**
* (ID: 124-127)
* 8
* 0-1 (0.01 Nm)
* 2-4 (0.0001 rad24)
* 5-7 (0.001 rad/s24)
*/
typedef struct {
int16_t torque_current; // 转矩电流 * 100
int32_t position; // 位置 * 10000 (仅使用低24位)
int32_t velocity; // 速度 * 1000 (仅使用低24位)
} Virtual_Chassis_JointFeedback_t;
/**
* (ID: 130-131)
* 8
* 0-1 (0.01)
* 2-3 (1dps)
* 4-5
* 6-7
*/
typedef struct {
int16_t angle_deg; // 角度 * 100 (度)
int16_t velocity_dps; // 速度 (度/秒)
int16_t torque_current; // 力矩电流
uint16_t encoder; // 编码器值
} Virtual_Chassis_WheelFeedback_t;
/**
* (ID: 0x301)
* 6
* 0.01g
*/
typedef struct {
int16_t x; // X轴加速度 * 100
int16_t y; // Y轴加速度 * 100
int16_t z; // Z轴加速度 * 100
} Virtual_Chassis_AcclData_t;
/**
* (ID: 0x302)
* 6
* 0.01°/s
*/
typedef struct {
int16_t x; // X轴角速度 * 100 (°/s)
int16_t y; // Y轴角速度 * 100 (°/s)
int16_t z; // Z轴角速度 * 100 (°/s)
} Virtual_Chassis_GyroData_t;
/**
* (ID: 0x303)
* 6
* 0.01°
*/
typedef struct {
int16_t yaw; // 偏航角 * 100 (°)
int16_t pitch; // 俯仰角 * 100 (°)
int16_t roll; // 横滚角 * 100 (°)
} Virtual_Chassis_EulerData_t;
/**
* (ID: 0x304)
* 8
* 1/32000
*/
typedef struct {
int16_t q0; // q0 * 32000
int16_t q1; // q1 * 32000
int16_t q2; // q2 * 32000
int16_t q3; // q3 * 32000
} Virtual_Chassis_QuatData_t;
#ifdef __cplusplus
}
#endif