chore: 导入 Simba-OmniInfantry 基线(云台/底盘双工程)

- 云台(ROBOT_TYPE_GIMBAL)与底盘(ROBOT_TYPE_CHASSIS)完整固件源码
- 新增根级 .gitignore,排除 Keil MDK-ARM 构建产物(.o/.d/.crf/.axf/.lnp/.map/.htm/.sct/.dep/.iex/.lst 等)
  与 *.uvguix.* / DebugConfig/(与机器绑定的 UI 布局)
- core.autocrlf=false,避免固件源码在检出时被改动换行符
This commit is contained in:
2026-09-12 10:28:21 +08:00
commit a4da5ad17c
517 changed files with 503795 additions and 0 deletions
+197
View File
@@ -0,0 +1,197 @@
/* =============================================================================
* c_comm.c - 云台<->底盘 板间通讯(CToC,CAN2,帧 ID 与 legacy 完全一致)
* 帧: 0x149 云->底 摇杆(4 个大端 u16) 0x189 云->底 控制状态
* 0x019 底->云 发射机构上电状态
* 云台板(主机): c_comm_master_send() 每 2ms 发摇杆帧+状态帧;
* 键鼠在线时按 legacy 规则把 WASD/鼠标合成进摇杆量;
* Data[0] 必须实时判定 dr16_offline()(dr16_status 掉线后不会自己清零)
* 底盘板(从机): c_comm_slave_send() 每 2ms 回传发射机构状态;
* 中断内解析 0x149/0x189 填充 ctoc_remote(底盘的"虚拟遥控器")
* ========================================================================== */
#include "c_comm.h"
#include "robot_param.h"
#include "referee.h"
#include <string.h>
volatile ctoc_remote_t ctoc_remote;
volatile uint8_t ctoc_shooter_power = 1;
volatile uint32_t ctoc_reply_last_tick = 0;
volatile uint8_t ctoc_remote_fault = 0;
volatile float ctoc_gimbal_yaw = 0.0f;
volatile uint8_t ctoc_att_ready = 0;
static volatile uint32_t ctoc_att_last_tick = 0;
/* 云台自检下发的编码器方向:+1=tick增向CCW -1=CW 0=未检测(0x1A9 flags) */
volatile int8_t ctoc_encoder_ccw = 0;
/* 0x1A9 帧新鲜判定(两板公共:底盘跟随用它门控,云台留作诊断) */
uint8_t ctoc_att_fresh(void)
{
return (ctoc_att_last_tick != 0 &&
HAL_GetTick() - ctoc_att_last_tick < CTOC_OFFLINE_TIME_MS);
}
static void c_comm_pack_uint16(uint8_t data[8], const uint16_t val[4])
{
for (uint8_t i = 0; i < 4; i++)
{
data[2 * i] = (uint8_t)(val[i] >> 8);
data[2 * i + 1] = (uint8_t)(val[i] & 0xFF);
}
}
static void c_comm_send_frame(hcan_t * hcan, uint32_t std_id, const uint8_t data[8])
{
CanCtrlData_s msg;
msg.hcan = hcan;
msg.tx_header.StdId = std_id;
msg.tx_header.IDE = CAN_ID_STD;
msg.tx_header.RTR = CAN_RTR_DATA;
msg.tx_header.DLC = 8;
msg.tx_header.TransmitGlobalTime = DISABLE;
for (uint8_t i = 0; i < 8; i++)
msg.tx_data[i] = data[i];
CAN_SendTxMessage(&msg);
}
#if defined(ROBOT_TYPE_GIMBAL)
/* ============================ 云台板(主机) ============================ */
static void c_comm_rx_0x019(uint32_t std_id, const uint8_t rx_data[8], uint32_t dlc)
{
(void)std_id;
(void)dlc;
ctoc_shooter_power = rx_data[0]; // 发射机构上电状态
ctoc_remote_fault = rx_data[1] & 0x01; // 底盘电机故障位
ctoc_reply_last_tick = HAL_GetTick();
}
void c_comm_init(void)
{
can_rx_register(&hcan2, CTOC_MASTER_ID1, c_comm_rx_0x019);
}
uint8_t ctoc_chassis_fault(void)
{
/* 从未收到过 0x019 视为底盘不在场,不判故障(便于仅云台台架调试);
* 收到过之后,故障位或帧超时都判故障 */
if (ctoc_reply_last_tick == 0)
return 0;
if (HAL_GetTick() - ctoc_reply_last_tick > CTOC_OFFLINE_TIME_MS)
return 1;
return ctoc_remote_fault;
}
/* 云台板:0x1A9 姿态帧 */
void c_comm_master_send_attitude(float yaw_deg, uint8_t flags)
{
uint8_t data[8] = {0};
memcpy(data, &yaw_deg, 4); // float 小端
data[4] = flags;
c_comm_send_frame(&hcan2, CTOC_SLAVE_ID3, data);
}
void c_comm_master_send(uint8_t keyboard_online, const uint8_t kb[12], uint8_t motor_fault, uint8_t spin_enable)
{
uint8_t data[8];
if (!keyboard_online)
{
// 遥控器控制:直接转发原始摇杆值
const uint16_t sticks[4] = {dr16.rc_r_RL, dr16.rc_r_UD, dr16.rc_l_RL, dr16.rc_l_UD};
c_comm_pack_uint16(data, sticks);
}
else
{
// 键鼠控制:合成摇杆量(与 legacy 一致)
uint8_t key_go = kb[8] & 0x01;
uint8_t key_back = (kb[8] >> 1) & 0x01;
uint8_t key_left = (kb[8] >> 2) & 0x01;
uint8_t key_right = (kb[8] >> 3) & 0x01;
int16_t mouse_rl = (int16_t)(((uint16_t)kb[1] << 8) | kb[0]);
int16_t mouse_du = (int16_t)(((uint16_t)kb[3] << 8) | kb[2]);
const uint16_t sticks[4] = {
(uint16_t)(1024 + (key_right - key_left) * 660), // AD->右摇杆RL
(uint16_t)(1024 + (key_go - key_back) * 660), // WS->右摇杆UD
(uint16_t)(1024 + mouse_rl * PC_MOUSE_RL_SENSITIVITY), // 鼠标->左摇杆RL
(uint16_t)(1024 + mouse_du * PC_MOUSE_DU_SENSITIVITY), // 鼠标->左摇杆UD
};
c_comm_pack_uint16(data, sticks);
}
c_comm_send_frame(&hcan2, CTOC_SLAVE_ID1, data);
/* 在线状态必须实时判定:dr16_status 只在收帧时置 1,掉线后不会自己清零,
* 若直接转发会让底盘永远认为遥控器在线(停车保护失效) */
data[0] = (dr16_status && !dr16_offline()) ? 1 : 0;
data[1] = dr16.s2;
data[2] = dr16.key_push_ctrl;
data[3] = dr16.key_push_shift;
data[4] = dr16_start_flag;
data[5] = dr16.s1;
data[6] = (motor_fault ? 0x80 : 0) | (spin_enable ? 0x04 : 0) |
(dr16.key_alpha1 ? 0x01 : 0) |
(dr16.key_alpha2 ? 0x02 : 0); // bit7=故障 bit2=陀螺使能(扩展)
data[7] = 0;
c_comm_send_frame(&hcan2, CTOC_SLAVE_ID2, data);
}
#elif defined(ROBOT_TYPE_CHASSIS)
/* ============================ 底盘板(从机) ============================ */
static void c_comm_rx_0x149(uint32_t std_id, const uint8_t rx_data[8], uint32_t dlc)
{
(void)std_id;
(void)dlc;
ctoc_remote.rc_r_rl = ((uint16_t)rx_data[0] << 8) | rx_data[1];
ctoc_remote.rc_r_ud = ((uint16_t)rx_data[2] << 8) | rx_data[3];
ctoc_remote.rc_l_rl = ((uint16_t)rx_data[4] << 8) | rx_data[5];
ctoc_remote.rc_l_ud = ((uint16_t)rx_data[6] << 8) | rx_data[7];
ctoc_remote.last_tick = HAL_GetTick();
}
static void c_comm_rx_0x189(uint32_t std_id, const uint8_t rx_data[8], uint32_t dlc)
{
(void)std_id;
(void)dlc;
ctoc_remote.status = rx_data[0];
ctoc_remote.s2 = rx_data[1];
ctoc_remote.ctrl_push = rx_data[2];
ctoc_remote.shift_push = rx_data[3];
ctoc_remote.start_flag = rx_data[4];
ctoc_remote.s1 = rx_data[5];
ctoc_remote.spin_flag = (rx_data[6] >> 2) & 0x01; // 小陀螺使能位
ctoc_remote.gimbal_fault = (rx_data[6] & 0x80) ? 1 : 0; // 云台电机故障位
ctoc_remote.last_tick = HAL_GetTick();
}
static void c_comm_rx_0x1a9(uint32_t std_id, const uint8_t rx_data[8], uint32_t dlc)
{
(void)std_id;
(void)dlc;
float yaw;
memcpy(&yaw, rx_data, 4);
ctoc_gimbal_yaw = yaw;
ctoc_att_ready = rx_data[4] & 0x01;
if (rx_data[4] & 0x04) // 云台自检完成位
ctoc_encoder_ccw = (rx_data[4] & 0x02) ? 1 : -1; // tick 增方向
ctoc_att_last_tick = HAL_GetTick();
}
void c_comm_init(void)
{
can_rx_register(&hcan2, CTOC_SLAVE_ID1, c_comm_rx_0x149);
can_rx_register(&hcan2, CTOC_SLAVE_ID2, c_comm_rx_0x189);
can_rx_register(&hcan2, CTOC_SLAVE_ID3, c_comm_rx_0x1a9);
}
void c_comm_slave_send(uint8_t motor_fault)
{
uint8_t data[8] = {0};
data[0] = referee.shooter_power_on; // 发射机构上电状态
data[1] = motor_fault ? 0x01 : 0; // 底盘电机故障位(扩展)
c_comm_send_frame(&hcan2, CTOC_MASTER_ID1, data);
}
#endif
+79
View File
@@ -0,0 +1,79 @@
#ifndef C_COMM_H
#define C_COMM_H
#include <stdint.h>
#include "bsp_can.h"
#include "dr16.h"
/* 云台<->底盘 板间通讯(CToC),帧 ID 与 legacy 完全一致
* 0x149 云台->底盘:Data[0..1]右摇杆RL [2..3]右摇杆UD [4..5]左摇杆RL [6..7]左摇杆UD(大端16bit)
* 0x189 云台->底盘:Data[0]遥控状态 [1]S2 [3]Shift翻转 [4]启动标志 [5]S1
* Data[2] 保留(原 Ctrl 翻转态——沿检测已移至云台侧,
* 底盘误判沿会误开小陀螺,勿再使用)
* Data[6] bit0=键1 bit1=键2 bit2=小陀螺使能(本工程扩展)
* bit7=云台电机故障(本工程扩展)
* 0x1A9 云台->底盘:Data[0..3]=云台世界系 yaw(float,LE) Data[4]=att_ready
* (双 INS 跟随方案的数据源,2026-09 新增)
* 0x1A9 云台->底盘:Data[0..3]=云台世界系 yaw(float,LE)
* Data[4] flags:bit0=att_ready bit1=编码器tick增向为CCW
* bit2=该位有效(自检完成) [跟随符号自动综合的数据源]
* 0x019 底盘->云台:Data[0]发射机构上电状态 Data[1] bit0=底盘电机故障(本工程扩展)
*
* 故障位语义:任一侧电机掉线即置位,对侧收到后必须停止自己的输出(整车安全) */
/* 底盘板:从 0x149/0x189 解析出的"虚拟遥控器"数据(布局同 dr16_t 的子集) */
typedef struct
{
uint16_t rc_r_rl;
uint16_t rc_r_ud;
uint16_t rc_l_rl;
uint16_t rc_l_ud;
uint8_t s1;
uint8_t s2;
uint8_t ctrl_push;
uint8_t shift_push;
uint8_t start_flag;
uint8_t status; // 云台侧遥控器在线状态
uint8_t spin_flag; // 小陀螺使能(0x189 Data[6] bit2,云台侧沿检测)
uint8_t gimbal_fault; // 云台电机故障标志(0x189 Data[6] bit7)
uint32_t last_tick; // 最近收帧 tick(掉线检测)
} ctoc_remote_t;
extern volatile ctoc_remote_t ctoc_remote;
/* 云台板:底盘回传的发射机构上电状态 */
extern volatile uint8_t ctoc_shooter_power;
/* 云台板:最近收到 0x019 的 tick(掉线检测/诊断) */
extern volatile uint32_t ctoc_reply_last_tick;
/* 云台板:底盘电机故障标志(0x019 Data[1] bit0,ISR 内更新) */
extern volatile uint8_t ctoc_remote_fault;
/* 云台板:底盘故障综合判定(故障位置位 或 0x019 超时;从未收到过 0x019
* 视为底盘不在场不判故障,便于仅云台台架调试) */
extern uint8_t ctoc_chassis_fault(void);
/* 云台板:发送 0x1A9 姿态帧(2ms 周期,c_comm_task 调用)
* yaw_deg 为世界系多圈角(att_deg_yaw),flags bit0=att_ready */
extern void c_comm_master_send_attitude(float yaw_deg, uint8_t flags);
/* 底盘板:云台姿态(0x1A9 解析,ISR 内更新) */
extern volatile float ctoc_gimbal_yaw;
extern volatile uint8_t ctoc_att_ready;
/* 云台自检的编码器方向:+1=tick增向CCW -1=CW 0=未检测 */
extern volatile int8_t ctoc_encoder_ccw;
/* 底盘板:0x1A9 帧是否新鲜(掉线检测) */
extern uint8_t ctoc_att_fresh(void);
/* 注册 CAN 接收回调(can_start() 之后调用) */
extern void c_comm_init(void);
/* 云台板:发送摇杆帧与控制状态帧(2ms 周期,keyboard_online=1 时用键鼠合成量替代摇杆)
* kb 参数为图传 0x0304 解析出的键鼠数据(keyboard_online 时有效),布局:
* [0..1]鼠标X [2..3]鼠标Y [4..5]滚轮 [6]左键 [7]右键 [8]键位bitmap
* motor_fault:本板电机掉线标志,随 0x189 Data[6] bit7 广播 */
extern void c_comm_master_send(uint8_t keyboard_online, const uint8_t kb[12], uint8_t motor_fault, uint8_t spin_enable);
/* 底盘板:回传发射机构状态与底盘电机故障位(2ms 周期) */
extern void c_comm_slave_send(uint8_t motor_fault);
#endif