From fd58bb0462cf772df4a6808ca1903e48fe2307e1 Mon Sep 17 00:00:00 2001 From: Robofish <1683502971@qq.com> Date: Tue, 30 Sep 2025 16:32:29 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=99=80=E8=9E=BA=E4=BB=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- User/device/dr16.c | 6 +- User/device/dr16.h | 48 ++-- User/device/rc_can.c | 541 ++++++++++++++++++++++++++++++++++++++++++ User/device/rc_can.h | 251 +++++++++++++++++++- User/module/config.c | 21 +- User/module/shoot.c | 7 +- User/task/atti_esti.c | 36 +++ User/task/rc.c | 6 +- 8 files changed, 861 insertions(+), 55 deletions(-) diff --git a/User/device/dr16.c b/User/device/dr16.c index 929e4b5..120997b 100644 --- a/User/device/dr16.c +++ b/User/device/dr16.c @@ -141,13 +141,13 @@ int8_t DR16_ParseData(DR16_t *dr16){ uint16_t key_value = dr16->raw_data.key; // 解析键盘位映射(W-B键,位0-15) - for (int i = CMD_KEY_W; i <= CMD_KEY_B; i++) { + for (int i = DR16_KEY_W; i <= DR16_KEY_B; i++) { dr16->data.keyboard.key[i] = (key_value & (1 << i)) != 0; } // 解析鼠标点击 - dr16->data.keyboard.key[CMD_L_CLICK] = dr16->data.mouse.l_click; - dr16->data.keyboard.key[CMD_R_CLICK] = dr16->data.mouse.r_click; + dr16->data.keyboard.key[DR16_L_CLICK] = dr16->data.mouse.l_click; + dr16->data.keyboard.key[DR16_R_CLICK] = dr16->data.mouse.r_click; // 解析第五通道 dr16->data.ch_res = 2.0f * ((float)dr16->raw_data.res - DR16_CH_VALUE_MID) / full_range; diff --git a/User/device/dr16.h b/User/device/dr16.h index 6e40c94..03fa526 100644 --- a/User/device/dr16.h +++ b/User/device/dr16.h @@ -38,33 +38,33 @@ typedef struct __packed { } DR16_RawData_t; typedef enum { - CMD_SW_ERR = 0, - CMD_SW_UP = 1, - CMD_SW_MID = 3, - CMD_SW_DOWN = 2, + DR16_SW_ERR = 0, + DR16_SW_UP = 1, + DR16_SW_MID = 3, + DR16_SW_DOWN = 2, } DR16_SwitchPos_t; /* 键盘按键值 */ typedef enum { - CMD_KEY_W = 0, - CMD_KEY_S, - CMD_KEY_A, - CMD_KEY_D, - CMD_KEY_SHIFT, - CMD_KEY_CTRL, - CMD_KEY_Q, - CMD_KEY_E, - CMD_KEY_R, - CMD_KEY_F, - CMD_KEY_G, - CMD_KEY_Z, - CMD_KEY_X, - CMD_KEY_C, - CMD_KEY_V, - CMD_KEY_B, - CMD_L_CLICK, - CMD_R_CLICK, - CMD_KEY_NUM, + DR16_KEY_W = 0, + DR16_KEY_S, + DR16_KEY_A, + DR16_KEY_D, + DR16_KEY_SHIFT, + DR16_KEY_CTRL, + DR16_KEY_Q, + DR16_KEY_E, + DR16_KEY_R, + DR16_KEY_F, + DR16_KEY_G, + DR16_KEY_Z, + DR16_KEY_X, + DR16_KEY_C, + DR16_KEY_V, + DR16_KEY_B, + DR16_L_CLICK, + DR16_R_CLICK, + DR16_KEY_NUM, } DR16_Key_t; typedef struct { @@ -87,7 +87,7 @@ typedef struct { } mouse; /* 鼠标值 */ union { - bool key[CMD_KEY_NUM]; /* 键盘按键值 */ + bool key[DR16_KEY_NUM]; /* 键盘按键值 */ uint16_t value; /* 键盘按键值的位映射 */ } keyboard; diff --git a/User/device/rc_can.c b/User/device/rc_can.c index e69de29..c03410f 100644 --- a/User/device/rc_can.c +++ b/User/device/rc_can.c @@ -0,0 +1,541 @@ +/* + RC CAN数据发送模块 + 将DR16遥控器数据通过CAN总线发送 + 参考motor_rm的结构设计 + + Example: + + RC_CAN_t rc_can; + RC_CAN_Param_t param = { + .can = BSP_CAN_1, + .enabled = true, + .send_period = 10 // 10ms发送一次 + }; + + RC_CAN_Init(&rc_can, ¶m); + + // 在主循环中 + while(1) { + if (DR16_ParseData(&dr16) == DEVICE_OK) { + RC_CAN_SendData(&rc_can, &dr16); + } + osDelay(param.send_period); + } +*/ + +/* Includes ----------------------------------------------------------------- */ +#include "rc_can.h" +#include "device/dr16.h" +#include "bsp/time.h" +#include + +/* USER INCLUDE BEGIN */ + +/* USER INCLUDE END */ + +/* Private define ----------------------------------------------------------- */ +#define RC_CAN_SCALE_FACTOR 1000.0f // 将[-1.0, 1.0]转换为[-1000, 1000] +#define RC_CAN_DATA_JOYSTICK 0 +#define RC_CAN_DATA_SWITCH 1 +#define RC_CAN_DATA_MOUSE 2 +#define RC_CAN_DATA_KEYBOARD 3 +#define RC_CAN_DATA_STATUS 4 + +/* USER DEFINE BEGIN */ + +/* USER DEFINE END */ + +/* Private macro ------------------------------------------------------------ */ +/* Private typedef ---------------------------------------------------------- */ +/* Private variables -------------------------------------------------------- */ + +/* Private function -------------------------------------------------------- */ + +/** + * @brief 将浮点数转换为整数,缩放到指定范围 + * @param value 输入值 [-1.0, 1.0] + * @return 缩放后的整数值 [-1000, 1000] + */ +static int16_t RC_CAN_ScaleFloat(float value) { + if (value > 1.0f) value = 1.0f; + if (value < -1.0f) value = -1.0f; + return (int16_t)(value * RC_CAN_SCALE_FACTOR); +} + +/** + * @brief 更新遥杆数据 + * @param rc_can RC_CAN结构体指针 + * @param dr16 DR16数据结构体指针 + */ +static void RC_CAN_UpdateJoystickData(RC_CAN_t *rc_can, const DR16_t *dr16) { + rc_can->joystick_data.ch_l_x = RC_CAN_ScaleFloat(dr16->data.ch_l_x); + rc_can->joystick_data.ch_l_y = RC_CAN_ScaleFloat(dr16->data.ch_l_y); + rc_can->joystick_data.ch_r_x = RC_CAN_ScaleFloat(dr16->data.ch_r_x); + rc_can->joystick_data.ch_r_y = RC_CAN_ScaleFloat(dr16->data.ch_r_y); +} + +/** + * @brief 更新拨杆数据 + * @param rc_can RC_CAN结构体指针 + * @param dr16 DR16数据结构体指针 + */ +static void RC_CAN_UpdateSwitchData(RC_CAN_t *rc_can, const DR16_t *dr16) { + rc_can->switch_data.sw_l = (uint8_t)dr16->data.sw_l; + rc_can->switch_data.sw_r = (uint8_t)dr16->data.sw_r; + rc_can->switch_data.ch_res = RC_CAN_ScaleFloat(dr16->data.ch_res); + rc_can->switch_data.reserved = 0; +} + +/** + * @brief 更新鼠标数据 + * @param rc_can RC_CAN结构体指针 + * @param dr16 DR16数据结构体指针 + */ +static void RC_CAN_UpdateMouseData(RC_CAN_t *rc_can, const DR16_t *dr16) { + rc_can->mouse_data.mouse_x = dr16->data.mouse.x; + rc_can->mouse_data.mouse_y = dr16->data.mouse.y; + rc_can->mouse_data.mouse_z = dr16->data.mouse.z; + rc_can->mouse_data.mouse_l = dr16->data.mouse.l_click ? 1 : 0; + rc_can->mouse_data.mouse_r = dr16->data.mouse.r_click ? 1 : 0; +} + +/** + * @brief 更新键盘数据 + * @param rc_can RC_CAN结构体指针 + * @param dr16 DR16数据结构体指针 + */ +static void RC_CAN_UpdateKeyboardData(RC_CAN_t *rc_can, const DR16_t *dr16) { + rc_can->keyboard_data.key_value = dr16->data.keyboard.value; + memset(rc_can->keyboard_data.reserved, 0, sizeof(rc_can->keyboard_data.reserved)); +} + +/** + * @brief 更新状态数据 + * @param rc_can RC_CAN结构体指针 + * @param dr16 DR16数据结构体指针 + */ +static void RC_CAN_UpdateStatusData(RC_CAN_t *rc_can, const DR16_t *dr16) { + rc_can->status_data.online = dr16->header.online ? 1 : 0; + rc_can->status_data.data_valid = 1; // 假设数据有效 + rc_can->status_data.timestamp = (uint32_t)(BSP_TIME_Get() / 1000); // 转换为ms + rc_can->status_data.reserved = 0; +} + +/** + * @brief 将整数转换为浮点数,反缩放 + * @param value 输入值 [-1000, 1000] + * @return 反缩放后的浮点数值 [-1.0, 1.0] + */ +static float RC_CAN_UnscaleInt(int16_t value) { + float result = (float)value / RC_CAN_SCALE_FACTOR; + if (result > 1.0f) result = 1.0f; + if (result < -1.0f) result = -1.0f; + return result; +} + +/** + * @brief 处理接收到的CAN消息 + * @param rc_can RC_CAN结构体指针 + * @param msg CAN消息指针 + */ +static void RC_CAN_ProcessRxMessage(RC_CAN_t *rc_can, BSP_CAN_Message_t *msg) { + uint32_t current_time = (uint32_t)(BSP_TIME_Get() / 1000); // 转换为ms + + switch (msg->parsed_id) { + case RC_CAN_DR16_JOYSTICK_ID: + if (msg->dlc >= sizeof(RC_CAN_JoystickData_t)) { + memcpy(&rc_can->joystick_data, msg->data, sizeof(RC_CAN_JoystickData_t)); + rc_can->rx_status.joystick_updated = true; + rc_can->rx_status.last_joystick_time = current_time; + } + break; + + case RC_CAN_DR16_SWITCH_ID: + if (msg->dlc >= sizeof(RC_CAN_SwitchData_t)) { + memcpy(&rc_can->switch_data, msg->data, sizeof(RC_CAN_SwitchData_t)); + rc_can->rx_status.switch_updated = true; + rc_can->rx_status.last_switch_time = current_time; + } + break; + + case RC_CAN_DR16_MOUSE_ID: + if (msg->dlc >= sizeof(RC_CAN_MouseData_t)) { + memcpy(&rc_can->mouse_data, msg->data, sizeof(RC_CAN_MouseData_t)); + rc_can->rx_status.mouse_updated = true; + rc_can->rx_status.last_mouse_time = current_time; + } + break; + + case RC_CAN_DR16_KEYBOARD_ID: + if (msg->dlc >= sizeof(RC_CAN_KeyboardData_t)) { + memcpy(&rc_can->keyboard_data, msg->data, sizeof(RC_CAN_KeyboardData_t)); + rc_can->rx_status.keyboard_updated = true; + rc_can->rx_status.last_keyboard_time = current_time; + } + break; + + case RC_CAN_DR16_STATUS_ID: + if (msg->dlc >= sizeof(RC_CAN_StatusData_t)) { + memcpy(&rc_can->status_data, msg->data, sizeof(RC_CAN_StatusData_t)); + rc_can->rx_status.status_updated = true; + rc_can->rx_status.last_status_time = current_time; + // 更新整体在线状态 + rc_can->header.online = (rc_can->status_data.online == 1); + rc_can->header.last_online_time = BSP_TIME_Get(); + } + break; + + default: + // 未知ID,忽略 + break; + } +} + +/* USER FUNCTION BEGIN */ + +/* USER FUNCTION END */ + +/* Exported functions ------------------------------------------------------- */ + +int8_t RC_CAN_Init(RC_CAN_t *rc_can, RC_CAN_Param_t *param) { + if (rc_can == NULL || param == NULL) { + return DEVICE_ERR_NULL; + } + + if (rc_can->initialized) { + return DEVICE_ERR_INITED; + } + + // 复制参数 + memcpy(&rc_can->param, param, sizeof(RC_CAN_Param_t)); + + // 初始化头部信息 + rc_can->header.online = false; + rc_can->header.last_online_time = 0; + + // 清零数据包 + memset(&rc_can->joystick_data, 0, sizeof(RC_CAN_JoystickData_t)); + memset(&rc_can->switch_data, 0, sizeof(RC_CAN_SwitchData_t)); + memset(&rc_can->mouse_data, 0, sizeof(RC_CAN_MouseData_t)); + memset(&rc_can->keyboard_data, 0, sizeof(RC_CAN_KeyboardData_t)); + memset(&rc_can->status_data, 0, sizeof(RC_CAN_StatusData_t)); + + // 初始化接收状态 + memset(&rc_can->rx_status, 0, sizeof(RC_CAN_RxStatus_t)); + + // 如果是接收模式,注册CAN ID + if (param->mode == RC_CAN_MODE_RECEIVER || param->mode == RC_CAN_MODE_BOTH) { + BSP_CAN_RegisterId(param->can, RC_CAN_DR16_JOYSTICK_ID, 0); + BSP_CAN_RegisterId(param->can, RC_CAN_DR16_SWITCH_ID, 0); + BSP_CAN_RegisterId(param->can, RC_CAN_DR16_MOUSE_ID, 0); + BSP_CAN_RegisterId(param->can, RC_CAN_DR16_KEYBOARD_ID, 0); + BSP_CAN_RegisterId(param->can, RC_CAN_DR16_STATUS_ID, 0); + } + + // 初始化状态 + rc_can->last_send_time = 0; + rc_can->initialized = true; + + return DEVICE_OK; +} + +int8_t RC_CAN_SendData(RC_CAN_t *rc_can, const void *dr16_ptr) { + if (rc_can == NULL || dr16_ptr == NULL) { + return DEVICE_ERR_NULL; + } + + const DR16_t *dr16 = (const DR16_t *)dr16_ptr; + + if (!rc_can->initialized) { + return DEVICE_ERR; + } + + if (!rc_can->param.enabled) { + return DEVICE_OK; // 未启用时直接返回成功 + } + + uint64_t current_time = BSP_TIME_Get() / 1000; // 转换为ms + + // 检查发送周期 + if (current_time - rc_can->last_send_time < rc_can->param.send_period) { + return DEVICE_OK; // 未到发送时间 + } + + // 更新所有数据包 + RC_CAN_UpdateJoystickData(rc_can, dr16); + RC_CAN_UpdateSwitchData(rc_can, dr16); + RC_CAN_UpdateMouseData(rc_can, dr16); + RC_CAN_UpdateKeyboardData(rc_can, dr16); + RC_CAN_UpdateStatusData(rc_can, dr16); + + int8_t result = DEVICE_OK; + + // 发送所有数据包 + if (RC_CAN_SendJoystickData(rc_can) != DEVICE_OK) result = DEVICE_ERR; + if (RC_CAN_SendSwitchData(rc_can) != DEVICE_OK) result = DEVICE_ERR; + if (RC_CAN_SendMouseData(rc_can) != DEVICE_OK) result = DEVICE_ERR; + if (RC_CAN_SendKeyboardData(rc_can) != DEVICE_OK) result = DEVICE_ERR; + if (RC_CAN_SendStatusData(rc_can) != DEVICE_OK) result = DEVICE_ERR; + + // 更新发送时间和在线状态 + rc_can->last_send_time = (uint32_t)current_time; + rc_can->header.online = true; + rc_can->header.last_online_time = BSP_TIME_Get(); + + return result; +} + +int8_t RC_CAN_SendJoystickData(RC_CAN_t *rc_can) { + if (rc_can == NULL) { + return DEVICE_ERR_NULL; + } + + BSP_CAN_StdDataFrame_t tx_frame; + tx_frame.id = RC_CAN_DR16_JOYSTICK_ID; + tx_frame.dlc = sizeof(RC_CAN_JoystickData_t); + + memcpy(tx_frame.data, &rc_can->joystick_data, sizeof(RC_CAN_JoystickData_t)); + + return BSP_CAN_TransmitStdDataFrame(rc_can->param.can, &tx_frame) == BSP_OK ? + DEVICE_OK : DEVICE_ERR; +} + +int8_t RC_CAN_SendSwitchData(RC_CAN_t *rc_can) { + if (rc_can == NULL) { + return DEVICE_ERR_NULL; + } + + BSP_CAN_StdDataFrame_t tx_frame; + tx_frame.id = RC_CAN_DR16_SWITCH_ID; + tx_frame.dlc = sizeof(RC_CAN_SwitchData_t); + + memcpy(tx_frame.data, &rc_can->switch_data, sizeof(RC_CAN_SwitchData_t)); + + return BSP_CAN_TransmitStdDataFrame(rc_can->param.can, &tx_frame) == BSP_OK ? + DEVICE_OK : DEVICE_ERR; +} + +int8_t RC_CAN_SendMouseData(RC_CAN_t *rc_can) { + if (rc_can == NULL) { + return DEVICE_ERR_NULL; + } + + BSP_CAN_StdDataFrame_t tx_frame; + tx_frame.id = RC_CAN_DR16_MOUSE_ID; + tx_frame.dlc = sizeof(RC_CAN_MouseData_t); + + memcpy(tx_frame.data, &rc_can->mouse_data, sizeof(RC_CAN_MouseData_t)); + + return BSP_CAN_TransmitStdDataFrame(rc_can->param.can, &tx_frame) == BSP_OK ? + DEVICE_OK : DEVICE_ERR; +} + +int8_t RC_CAN_SendKeyboardData(RC_CAN_t *rc_can) { + if (rc_can == NULL) { + return DEVICE_ERR_NULL; + } + + BSP_CAN_StdDataFrame_t tx_frame; + tx_frame.id = RC_CAN_DR16_KEYBOARD_ID; + tx_frame.dlc = sizeof(RC_CAN_KeyboardData_t); + + memcpy(tx_frame.data, &rc_can->keyboard_data, sizeof(RC_CAN_KeyboardData_t)); + + return BSP_CAN_TransmitStdDataFrame(rc_can->param.can, &tx_frame) == BSP_OK ? + DEVICE_OK : DEVICE_ERR; +} + +int8_t RC_CAN_SendStatusData(RC_CAN_t *rc_can) { + if (rc_can == NULL) { + return DEVICE_ERR_NULL; + } + + BSP_CAN_StdDataFrame_t tx_frame; + tx_frame.id = RC_CAN_DR16_STATUS_ID; + tx_frame.dlc = sizeof(RC_CAN_StatusData_t); + + memcpy(tx_frame.data, &rc_can->status_data, sizeof(RC_CAN_StatusData_t)); + + return BSP_CAN_TransmitStdDataFrame(rc_can->param.can, &tx_frame) == BSP_OK ? + DEVICE_OK : DEVICE_ERR; +} + +int8_t RC_CAN_SetEnabled(RC_CAN_t *rc_can, bool enabled) { + if (rc_can == NULL) { + return DEVICE_ERR_NULL; + } + + rc_can->param.enabled = enabled; + return DEVICE_OK; +} + +bool RC_CAN_IsOnline(const RC_CAN_t *rc_can) { + if (rc_can == NULL) { + return false; + } + + return rc_can->header.online; +} + +int8_t RC_CAN_Update(RC_CAN_t *rc_can) { + if (rc_can == NULL) { + return DEVICE_ERR_NULL; + } + + if (!rc_can->initialized) { + return DEVICE_ERR; + } + + // 只在接收模式下处理接收 + if (rc_can->param.mode != RC_CAN_MODE_RECEIVER && rc_can->param.mode != RC_CAN_MODE_BOTH) { + return DEVICE_OK; + } + + BSP_CAN_Message_t rx_msg; + int8_t result = DEVICE_OK; + + // 处理所有可能的接收ID + uint32_t can_ids[] = { + RC_CAN_DR16_JOYSTICK_ID, + RC_CAN_DR16_SWITCH_ID, + RC_CAN_DR16_MOUSE_ID, + RC_CAN_DR16_KEYBOARD_ID, + RC_CAN_DR16_STATUS_ID + }; + + for (int i = 0; i < 5; i++) { + while (BSP_CAN_GetMessage(rc_can->param.can, can_ids[i], &rx_msg, BSP_CAN_TIMEOUT_IMMEDIATE) == BSP_OK) { + RC_CAN_ProcessRxMessage(rc_can, &rx_msg); + } + } + + return result; +} + +int8_t RC_CAN_GetJoystickData(const RC_CAN_t *rc_can, float *ch_l_x, float *ch_l_y, + float *ch_r_x, float *ch_r_y) { + if (rc_can == NULL || ch_l_x == NULL || ch_l_y == NULL || + ch_r_x == NULL || ch_r_y == NULL) { + return DEVICE_ERR_NULL; + } + + *ch_l_x = RC_CAN_UnscaleInt(rc_can->joystick_data.ch_l_x); + *ch_l_y = RC_CAN_UnscaleInt(rc_can->joystick_data.ch_l_y); + *ch_r_x = RC_CAN_UnscaleInt(rc_can->joystick_data.ch_r_x); + *ch_r_y = RC_CAN_UnscaleInt(rc_can->joystick_data.ch_r_y); + + return DEVICE_OK; +} + +int8_t RC_CAN_GetSwitchData(const RC_CAN_t *rc_can, uint8_t *sw_l, uint8_t *sw_r, + float *ch_res) { + if (rc_can == NULL || sw_l == NULL || sw_r == NULL || ch_res == NULL) { + return DEVICE_ERR_NULL; + } + + *sw_l = rc_can->switch_data.sw_l; + *sw_r = rc_can->switch_data.sw_r; + *ch_res = RC_CAN_UnscaleInt(rc_can->switch_data.ch_res); + + return DEVICE_OK; +} + +int8_t RC_CAN_GetMouseData(const RC_CAN_t *rc_can, int16_t *mouse_x, int16_t *mouse_y, + int16_t *mouse_z, bool *mouse_l, bool *mouse_r) { + if (rc_can == NULL || mouse_x == NULL || mouse_y == NULL || + mouse_z == NULL || mouse_l == NULL || mouse_r == NULL) { + return DEVICE_ERR_NULL; + } + + *mouse_x = rc_can->mouse_data.mouse_x; + *mouse_y = rc_can->mouse_data.mouse_y; + *mouse_z = rc_can->mouse_data.mouse_z; + *mouse_l = (rc_can->mouse_data.mouse_l != 0); + *mouse_r = (rc_can->mouse_data.mouse_r != 0); + + return DEVICE_OK; +} + +int8_t RC_CAN_GetKeyboardData(const RC_CAN_t *rc_can, uint16_t *key_value) { + if (rc_can == NULL || key_value == NULL) { + return DEVICE_ERR_NULL; + } + + *key_value = rc_can->keyboard_data.key_value; + + return DEVICE_OK; +} + +int8_t RC_CAN_GetRemoteStatus(const RC_CAN_t *rc_can, bool *remote_online, + bool *data_valid, uint32_t *timestamp) { + if (rc_can == NULL || remote_online == NULL || + data_valid == NULL || timestamp == NULL) { + return DEVICE_ERR_NULL; + } + + *remote_online = (rc_can->status_data.online != 0); + *data_valid = (rc_can->status_data.data_valid != 0); + *timestamp = rc_can->status_data.timestamp; + + return DEVICE_OK; +} + +bool RC_CAN_IsDataUpdated(RC_CAN_t *rc_can, uint8_t data_type) { + if (rc_can == NULL || data_type > RC_CAN_DATA_STATUS) { + return false; + } + + bool updated = false; + + switch (data_type) { + case RC_CAN_DATA_JOYSTICK: + updated = rc_can->rx_status.joystick_updated; + rc_can->rx_status.joystick_updated = false; // 清除更新标志 + break; + case RC_CAN_DATA_SWITCH: + updated = rc_can->rx_status.switch_updated; + rc_can->rx_status.switch_updated = false; + break; + case RC_CAN_DATA_MOUSE: + updated = rc_can->rx_status.mouse_updated; + rc_can->rx_status.mouse_updated = false; + break; + case RC_CAN_DATA_KEYBOARD: + updated = rc_can->rx_status.keyboard_updated; + rc_can->rx_status.keyboard_updated = false; + break; + case RC_CAN_DATA_STATUS: + updated = rc_can->rx_status.status_updated; + rc_can->rx_status.status_updated = false; + break; + default: + updated = false; + break; + } + + return updated; +} + +bool RC_CAN_IsDataTimeout(const RC_CAN_t *rc_can) { + if (rc_can == NULL) { + return true; + } + + uint32_t current_time = (uint32_t)(BSP_TIME_Get() / 1000); // 转换为ms + uint32_t timeout_ms = rc_can->param.timeout_ms; + + // 检查所有数据类型是否超时 + bool timeout = false; + + if (current_time - rc_can->rx_status.last_joystick_time > timeout_ms) timeout = true; + if (current_time - rc_can->rx_status.last_switch_time > timeout_ms) timeout = true; + if (current_time - rc_can->rx_status.last_mouse_time > timeout_ms) timeout = true; + if (current_time - rc_can->rx_status.last_keyboard_time > timeout_ms) timeout = true; + if (current_time - rc_can->rx_status.last_status_time > timeout_ms) timeout = true; + + return timeout; +} + +/* USER FUNCTION BEGIN */ + +/* USER FUNCTION END */ diff --git a/User/device/rc_can.h b/User/device/rc_can.h index 8e73fa7..71e8847 100644 --- a/User/device/rc_can.h +++ b/User/device/rc_can.h @@ -7,6 +7,9 @@ extern "C" { /* Includes ----------------------------------------------------------------- */ #include "bsp/can.h" #include "device/device.h" +#include +#include + /* USER INCLUDE BEGIN */ /* USER INCLUDE END */ @@ -16,6 +19,13 @@ extern "C" { /* USER DEFINE END */ /* Exported constants ------------------------------------------------------- */ +// CAN ID 定义 +#define RC_CAN_DR16_JOYSTICK_ID 0x300 // 遥杆数据 +#define RC_CAN_DR16_SWITCH_ID 0x301 // 拨杆数据 +#define RC_CAN_DR16_MOUSE_ID 0x302 // 鼠标数据 +#define RC_CAN_DR16_KEYBOARD_ID 0x303 // 键盘数据 +#define RC_CAN_DR16_STATUS_ID 0x304 // 状态数据 + /* Exported macro ----------------------------------------------------------- */ /* Exported types ----------------------------------------------------------- */ @@ -26,20 +36,94 @@ typedef enum { RC_CAN_SW_DOWN = 2, } RC_CAN_SW_t; -typedef struct { - float ch_l_x; - float ch_l_y; - float ch_r_x; - float ch_r_y; - RC_CAN_SW_t sw_l; - RC_CAN_SW_t sw_r; - flaot res; -} RC_CAN_DR16_t; +// 遥杆数据包 (CAN ID: 0x300) +typedef struct __packed { + int16_t ch_l_x; // 左侧摇杆X轴 (-1000~1000) + int16_t ch_l_y; // 左侧摇杆Y轴 (-1000~1000) + int16_t ch_r_x; // 右侧摇杆X轴 (-1000~1000) + int16_t ch_r_y; // 右侧摇杆Y轴 (-1000~1000) +} RC_CAN_JoystickData_t; -typedef struct { - f -} RC_CAN_DR16_t; +// 拨杆数据包 (CAN ID: 0x301) +typedef struct __packed { + uint8_t sw_l; // 左拨杆状态 + uint8_t sw_r; // 右拨杆状态 + int16_t ch_res; // 第五通道 (-1000~1000) + uint32_t reserved; // 保留字节 +} RC_CAN_SwitchData_t; +// 鼠标数据包 (CAN ID: 0x302) +typedef struct __packed { + int16_t mouse_x; // 鼠标X轴移动 + int16_t mouse_y; // 鼠标Y轴移动 + int16_t mouse_z; // 鼠标Z轴(滚轮) + uint8_t mouse_l; // 鼠标左键 + uint8_t mouse_r; // 鼠标右键 +} RC_CAN_MouseData_t; + +// 键盘数据包 (CAN ID: 0x303) +typedef struct __packed { + uint16_t key_value; // 键盘按键位映射 + uint8_t reserved[6]; // 保留字节 +} RC_CAN_KeyboardData_t; + +// 状态数据包 (CAN ID: 0x304) +typedef struct __packed { + uint8_t online; // 在线状态 (1:在线, 0:离线) + uint8_t data_valid; // 数据有效性 (1:有效, 0:无效) + uint32_t timestamp; // 时间戳(ms) + uint16_t reserved; // 保留字节 +} RC_CAN_StatusData_t; + +// 工作模式枚举 +typedef enum { + RC_CAN_MODE_SENDER, // 发送模式(连接DR16的板子) + RC_CAN_MODE_RECEIVER, // 接收模式(其他板子) + RC_CAN_MODE_BOTH // 双向模式(可发送也可接收) +} RC_CAN_Mode_t; + +// 接收数据状态 +typedef struct { + bool joystick_updated; + bool switch_updated; + bool mouse_updated; + bool keyboard_updated; + bool status_updated; + uint32_t last_joystick_time; + uint32_t last_switch_time; + uint32_t last_mouse_time; + uint32_t last_keyboard_time; + uint32_t last_status_time; +} RC_CAN_RxStatus_t; + +// RC_CAN 参数结构 +typedef struct { + BSP_CAN_t can; // 使用的CAN总线 + RC_CAN_Mode_t mode; // 工作模式 + bool enabled; // 是否启用发送(仅发送模式有效) + uint32_t send_period; // 发送周期(ms) + uint32_t timeout_ms; // 接收超时时间(ms) +} RC_CAN_Param_t; + +// RC_CAN 主结构 +typedef struct { + RC_CAN_Param_t param; + DEVICE_Header_t header; + + // 数据包 + RC_CAN_JoystickData_t joystick_data; + RC_CAN_SwitchData_t switch_data; + RC_CAN_MouseData_t mouse_data; + RC_CAN_KeyboardData_t keyboard_data; + RC_CAN_StatusData_t status_data; + + // 接收状态(仅接收模式有效) + RC_CAN_RxStatus_t rx_status; + + // 状态信息 + uint32_t last_send_time; + bool initialized; +} RC_CAN_t; /* USER STRUCT BEGIN */ @@ -47,6 +131,149 @@ typedef struct { /* Exported functions prototypes -------------------------------------------- */ +/** + * @brief 初始化RC CAN发送模块 + * @param rc_can RC_CAN结构体指针 + * @param param 初始化参数 + * @return DEVICE_OK 成功,其他值失败 + */ +int8_t RC_CAN_Init(RC_CAN_t *rc_can, RC_CAN_Param_t *param); + +/** + * @brief 更新并发送DR16数据到CAN总线 + * @param rc_can RC_CAN结构体指针 + * @param dr16 DR16数据结构体指针 + * @return DEVICE_OK 成功,其他值失败 + */ +int8_t RC_CAN_SendData(RC_CAN_t *rc_can, const void *dr16); + +/** + * @brief 发送遥杆数据 + * @param rc_can RC_CAN结构体指针 + * @return DEVICE_OK 成功,其他值失败 + */ +int8_t RC_CAN_SendJoystickData(RC_CAN_t *rc_can); + +/** + * @brief 发送拨杆数据 + * @param rc_can RC_CAN结构体指针 + * @return DEVICE_OK 成功,其他值失败 + */ +int8_t RC_CAN_SendSwitchData(RC_CAN_t *rc_can); + +/** + * @brief 发送鼠标数据 + * @param rc_can RC_CAN结构体指针 + * @return DEVICE_OK 成功,其他值失败 + */ +int8_t RC_CAN_SendMouseData(RC_CAN_t *rc_can); + +/** + * @brief 发送键盘数据 + * @param rc_can RC_CAN结构体指针 + * @return DEVICE_OK 成功,其他值失败 + */ +int8_t RC_CAN_SendKeyboardData(RC_CAN_t *rc_can); + +/** + * @brief 发送状态数据 + * @param rc_can RC_CAN结构体指针 + * @return DEVICE_OK 成功,其他值失败 + */ +int8_t RC_CAN_SendStatusData(RC_CAN_t *rc_can); + +/** + * @brief 设置发送使能状态 + * @param rc_can RC_CAN结构体指针 + * @param enabled 使能状态 + * @return DEVICE_OK 成功,其他值失败 + */ +int8_t RC_CAN_SetEnabled(RC_CAN_t *rc_can, bool enabled); + +/** + * @brief 获取在线状态 + * @param rc_can RC_CAN结构体指针 + * @return true 在线,false 离线 + */ +bool RC_CAN_IsOnline(const RC_CAN_t *rc_can); + +/** + * @brief 接收并更新CAN数据 + * @param rc_can RC_CAN结构体指针 + * @return DEVICE_OK 成功,其他值失败 + */ +int8_t RC_CAN_Update(RC_CAN_t *rc_can); + +/** + * @brief 获取遥杆数据(接收模式) + * @param rc_can RC_CAN结构体指针 + * @param ch_l_x 左摇杆X轴输出指针 + * @param ch_l_y 左摇杆Y轴输出指针 + * @param ch_r_x 右摇杆X轴输出指针 + * @param ch_r_y 右摇杆Y轴输出指针 + * @return DEVICE_OK 成功,其他值失败 + */ +int8_t RC_CAN_GetJoystickData(const RC_CAN_t *rc_can, float *ch_l_x, float *ch_l_y, + float *ch_r_x, float *ch_r_y); + +/** + * @brief 获取拨杆数据(接收模式) + * @param rc_can RC_CAN结构体指针 + * @param sw_l 左拨杆状态输出指针 + * @param sw_r 右拨杆状态输出指针 + * @param ch_res 第五通道输出指针 + * @return DEVICE_OK 成功,其他值失败 + */ +int8_t RC_CAN_GetSwitchData(const RC_CAN_t *rc_can, uint8_t *sw_l, uint8_t *sw_r, + float *ch_res); + +/** + * @brief 获取鼠标数据(接收模式) + * @param rc_can RC_CAN结构体指针 + * @param mouse_x 鼠标X轴输出指针 + * @param mouse_y 鼠标Y轴输出指针 + * @param mouse_z 鼠标Z轴输出指针 + * @param mouse_l 鼠标左键输出指针 + * @param mouse_r 鼠标右键输出指针 + * @return DEVICE_OK 成功,其他值失败 + */ +int8_t RC_CAN_GetMouseData(const RC_CAN_t *rc_can, int16_t *mouse_x, int16_t *mouse_y, + int16_t *mouse_z, bool *mouse_l, bool *mouse_r); + +/** + * @brief 获取键盘数据(接收模式) + * @param rc_can RC_CAN结构体指针 + * @param key_value 键盘按键位映射输出指针 + * @return DEVICE_OK 成功,其他值失败 + */ +int8_t RC_CAN_GetKeyboardData(const RC_CAN_t *rc_can, uint16_t *key_value); + +/** + * @brief 获取远程DR16状态(接收模式) + * @param rc_can RC_CAN结构体指针 + * @param remote_online 远程DR16在线状态输出指针 + * @param data_valid 数据有效性输出指针 + * @param timestamp 时间戳输出指针 + * @return DEVICE_OK 成功,其他值失败 + */ +int8_t RC_CAN_GetRemoteStatus(const RC_CAN_t *rc_can, bool *remote_online, + bool *data_valid, uint32_t *timestamp); + +/** + * @brief 检查数据是否有更新(接收模式) + * @param rc_can RC_CAN结构体指针 + * @param data_type 数据类型 (0:遥杆, 1:拨杆, 2:鼠标, 3:键盘, 4:状态) + * @return true 有更新,false 无更新 + */ +bool RC_CAN_IsDataUpdated(RC_CAN_t *rc_can, uint8_t data_type); + +/** + * @brief 检查数据是否超时(接收模式) + * @param rc_can RC_CAN结构体指针 + * @return true 超时,false 未超时 + */ +bool RC_CAN_IsDataTimeout(const RC_CAN_t *rc_can); + /* USER FUNCTION BEGIN */ /* USER FUNCTION END */ diff --git a/User/module/config.c b/User/module/config.c index ff247b4..d98e425 100644 --- a/User/module/config.c +++ b/User/module/config.c @@ -21,22 +21,22 @@ Config_RobotParam_t robot_config = { .shoot_param = { .trig_step_angle=M_2PI/8, .fric_motor_param[0] = { - .can = BSP_CAN_1, - .id = 0x205, - .module = MOTOR_M3508, - .reverse = false, - .gear=false, - }, - .fric_motor_param[1] = { - .can = BSP_CAN_1, - .id = 0x206, + .can = BSP_CAN_2, + .id = 0x201, .module = MOTOR_M3508, .reverse = true, .gear=false, }, + .fric_motor_param[1] = { + .can = BSP_CAN_2, + .id = 0x202, + .module = MOTOR_M3508, + .reverse = false, + .gear=false, + }, .trig_motor_param = { .can = BSP_CAN_1, - .id = 0x202, + .id = 0x201, .module = MOTOR_M2006, .reverse = false, .gear=true, @@ -80,7 +80,6 @@ Config_RobotParam_t robot_config = { .out = 30.0f, }, } - }; /* Private function prototypes ---------------------------------------------- */ diff --git a/User/module/shoot.c b/User/module/shoot.c index ba77a1e..8cee167 100644 --- a/User/module/shoot.c +++ b/User/module/shoot.c @@ -115,7 +115,9 @@ int8_t Shoot_Control(Shoot_t *c, const Shoot_CMD_t *cmd) case SHOOT_STATE_READY:/*准备射击*/ for(int i=0;i计算修正输出->加和、滤波、输出 */ - c->output.out_follow[i]=PID_Calc(&c->pid.fric_follow[i],c->target_variable.target_rpm/MAX_FRIC_RPM,c->feedback.fric_rpm[i],0,c->dt); + // c->output.out_follow[i]=PID_Calc(&c->pid.fric_follow[i],c->target_variable.target_rpm/MAX_FRIC_RPM,c->feedback.fric_rpm[i],0,c->dt); + c->output.out_follow[i]=PID_Calc(&c->pid.fric_follow[i],3000.0f/MAX_FRIC_RPM,c->feedback.fric_rpm[i],0,c->dt); + c->output.out_err[i]=PID_Calc(&c->pid.fric_err[i],c->feedback.fric_avgrpm,c->feedback.fric_rpm[i],0,c->dt); ScaleSumTo1(&c->output.out_follow[i], &c->output.out_err[i]); c->output.out_fric[i]=c->output.out_follow[i]+c->output.out_err[i]; @@ -138,7 +140,8 @@ int8_t Shoot_Control(Shoot_t *c, const Shoot_CMD_t *cmd) // c->target_variable.target_angle+=c->param->trig_step_angle; for(int i=0;ioutput.out_follow[i]=PID_Calc(&c->pid.fric_follow[i],c->target_variable.target_rpm/MAX_FRIC_RPM,c->feedback.fric_rpm[i],0,c->dt); + // c->output.out_follow[i]=PID_Calc(&c->pid.fric_follow[i],c->target_variable.target_rpm/MAX_FRIC_RPM,c->feedback.fric_rpm[i],0,c->dt); + c->output.out_follow[i]=PID_Calc(&c->pid.fric_follow[i],3000.0f/MAX_FRIC_RPM,c->feedback.fric_rpm[i],0,c->dt); c->output.out_err[i]=PID_Calc(&c->pid.fric_err[i],c->feedback.fric_avgrpm,c->feedback.fric_rpm[i],0,c->dt); ScaleSumTo1(&c->output.out_follow[i], &c->output.out_err[i]); c->output.out_fric[i]=c->output.out_follow[i]+c->output.out_err[i]; diff --git a/User/task/atti_esti.c b/User/task/atti_esti.c index 757ca94..b06d419 100644 --- a/User/task/atti_esti.c +++ b/User/task/atti_esti.c @@ -6,6 +6,10 @@ /* Includes ----------------------------------------------------------------- */ #include "task/user_task.h" /* USER INCLUDE BEGIN */ +#include "bsp/pwm.h" +#include "component/ahrs.h" +#include "component/pid.h" +#include "device/bmi088.h" /* USER INCLUDE END */ @@ -14,7 +18,17 @@ /* Private macro ------------------------------------------------------------ */ /* Private variables -------------------------------------------------------- */ /* USER STRUCT BEGIN */ +BMI088_t bmi088; +AHRS_t gimbal_ahrs; +AHRS_Magn_t magn; +AHRS_Eulr_t eulr_to_send; + +KPID_t imu_temp_ctrl_pid; + +BMI088_Cali_t cali_bmi088= { + .gyro_offset = {0.0f,0.0f,0.0f}, +}; /* USER STRUCT END */ /* Private function --------------------------------------------------------- */ @@ -26,11 +40,33 @@ void Task_atti_esti(void *argument) { osDelay(ATTI_ESTI_INIT_DELAY); /* 延时一段时间再开启任务 */ /* USER CODE INIT BEGIN */ + BMI088_Init(&bmi088,&cali_bmi088); + AHRS_Init(&gimbal_ahrs, &magn, BMI088_GetUpdateFreq(&bmi088)); /* USER CODE INIT END */ while (1) { /* USER CODE BEGIN */ + BMI088_WaitNew(); + BMI088_AcclStartDmaRecv(); + BMI088_AcclWaitDmaCplt(); + + BMI088_GyroStartDmaRecv(); + BMI088_GyroWaitDmaCplt(); + + /* 锁住RTOS内核防止数据解析过程中断,造成错误 */ + osKernelLock(); + /* 接收完所有数据后,把数据从原始字节加工成方便计算的数据 */ + BMI088_ParseAccl(&bmi088); + BMI088_ParseGyro(&bmi088); + // IST8310_Parse(&ist8310); + + /* 根据设备接收到的数据进行姿态解析 */ + AHRS_Update(&gimbal_ahrs, &bmi088.accl, &bmi088.gyro, &magn); + + /* 根据解析出来的四元数计算欧拉角 */ + AHRS_GetEulr(&eulr_to_send, &gimbal_ahrs); + osKernelUnlock(); /* USER CODE END */ } diff --git a/User/task/rc.c b/User/task/rc.c index f0fc1e3..5205d35 100644 --- a/User/task/rc.c +++ b/User/task/rc.c @@ -43,15 +43,15 @@ void Task_rc(void *argument) { } for_shoot.online = dr16.header.online; switch (dr16.data.sw_r) { - case CMD_SW_UP: + case DR16_SW_UP: for_shoot.ready = false; for_shoot.firecmd = false; break; - case CMD_SW_MID: + case DR16_SW_MID: for_shoot.ready = true; for_shoot.firecmd = false; break; - case CMD_SW_DOWN: + case DR16_SW_DOWN: for_shoot.ready = true; for_shoot.firecmd = true; break;