mirror of
https://github.com/goldenfishs/MRobot.git
synced 2025-12-20 14:51:35 +08:00
add-module-cmd(onlycode)
This commit is contained in:
parent
1ce8bf293c
commit
e0688293a7
265
module/cmd/cmd.c
Normal file
265
module/cmd/cmd.c
Normal file
@ -0,0 +1,265 @@
|
||||
/*
|
||||
* CMD 模块 V2 - 主控制模块实现
|
||||
*/
|
||||
#include "cmd.h"
|
||||
#include "bsp/time.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
/* ========================================================================== */
|
||||
/* 命令构建函数 */
|
||||
/* ========================================================================== */
|
||||
|
||||
/* 从RC输入生成底盘命令 */
|
||||
static void CMD_RC_BuildChassisCmd(CMD_t *ctx) {
|
||||
CMD_RCModeMap_t *map = &ctx->config->rc_mode_map;
|
||||
|
||||
/* 根据左拨杆位置选择模式 */
|
||||
switch (ctx->input.rc.sw[0]) {
|
||||
case CMD_SW_UP:
|
||||
ctx->output.chassis.cmd.mode = map->sw_left_up;
|
||||
break;
|
||||
case CMD_SW_MID:
|
||||
ctx->output.chassis.cmd.mode = map->sw_left_mid;
|
||||
break;
|
||||
case CMD_SW_DOWN:
|
||||
ctx->output.chassis.cmd.mode = map->sw_left_down;
|
||||
break;
|
||||
default:
|
||||
ctx->output.chassis.cmd.mode = CHASSIS_MODE_RELAX;
|
||||
break;
|
||||
}
|
||||
|
||||
/* 摇杆控制移动 */
|
||||
ctx->output.chassis.cmd.ctrl_vec.vx = ctx->input.rc.joy_right.x;
|
||||
ctx->output.chassis.cmd.ctrl_vec.vy = ctx->input.rc.joy_right.y;
|
||||
}
|
||||
|
||||
/* 从RC输入生成云台命令 */
|
||||
static void CMD_RC_BuildGimbalCmd(CMD_t *ctx) {
|
||||
CMD_RCModeMap_t *map = &ctx->config->rc_mode_map;
|
||||
|
||||
/* 根据拨杆选择云台模式 */
|
||||
switch (ctx->input.rc.sw[0]) {
|
||||
case CMD_SW_UP:
|
||||
ctx->output.gimbal.cmd.mode = map->gimbal_sw_up;
|
||||
break;
|
||||
case CMD_SW_MID:
|
||||
ctx->output.gimbal.cmd.mode = map->gimbal_sw_mid;
|
||||
break;
|
||||
case CMD_SW_DOWN:
|
||||
ctx->output.gimbal.cmd.mode = map->gimbal_sw_down;
|
||||
break;
|
||||
default:
|
||||
ctx->output.gimbal.cmd.mode = GIMBAL_MODE_RELAX;
|
||||
break;
|
||||
}
|
||||
|
||||
/* 左摇杆控制云台 */
|
||||
ctx->output.gimbal.cmd.delta_yaw = -ctx->input.rc.joy_left.x * 2.0f;
|
||||
ctx->output.gimbal.cmd.delta_pit = -ctx->input.rc.joy_left.y * 1.5f;
|
||||
}
|
||||
|
||||
/* 从RC输入生成射击命令 */
|
||||
static void CMD_RC_BuildShootCmd(CMD_t *ctx) {
|
||||
if (ctx->input.online[CMD_SRC_RC]) {
|
||||
ctx->output.shoot.cmd.mode = SHOOT_MODE_SINGLE;
|
||||
} else {
|
||||
ctx->output.shoot.cmd.mode = SHOOT_MODE_SAFE;
|
||||
}
|
||||
|
||||
/* 根据右拨杆控制射击 */
|
||||
switch (ctx->input.rc.sw[1]) {
|
||||
case CMD_SW_DOWN:
|
||||
ctx->output.shoot.cmd.ready = true;
|
||||
ctx->output.shoot.cmd.firecmd = true;
|
||||
break;
|
||||
case CMD_SW_MID:
|
||||
ctx->output.shoot.cmd.ready = true;
|
||||
ctx->output.shoot.cmd.firecmd = false;
|
||||
break;
|
||||
case CMD_SW_UP:
|
||||
default:
|
||||
ctx->output.shoot.cmd.ready = false;
|
||||
ctx->output.shoot.cmd.firecmd = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* 从PC输入生成底盘命令 */
|
||||
static void CMD_PC_BuildChassisCmd(CMD_t *ctx) {
|
||||
|
||||
if (!ctx->input.online[CMD_SRC_PC]) {
|
||||
ctx->output.chassis.cmd.mode = CHASSIS_MODE_RELAX;
|
||||
return;
|
||||
}
|
||||
|
||||
ctx->output.chassis.cmd.mode = CHASSIS_MODE_FOLLOW_GIMBAL;
|
||||
|
||||
/* WASD控制移动 */
|
||||
ctx->output.chassis.cmd.ctrl_vec.vx = 0.0f;
|
||||
ctx->output.chassis.cmd.ctrl_vec.vy = 0.0f;
|
||||
CMD_Behavior_ProcessAll(ctx, &ctx->input, &ctx->last_input, CMD_MODULE_CHASSIS);
|
||||
}
|
||||
|
||||
/* 从PC输入生成云台命令 */
|
||||
static void CMD_PC_BuildGimbalCmd(CMD_t *ctx) {
|
||||
CMD_Sensitivity_t *sens = &ctx->config->sensitivity;
|
||||
|
||||
if (!ctx->input.online[CMD_SRC_PC]) {
|
||||
ctx->output.gimbal.cmd.mode = GIMBAL_MODE_RELAX;
|
||||
return;
|
||||
}
|
||||
|
||||
ctx->output.gimbal.cmd.mode = GIMBAL_MODE_ABSOLUTE;
|
||||
|
||||
/* 鼠标控制云台 */
|
||||
ctx->output.gimbal.cmd.delta_yaw = (float)-ctx->input.pc.mouse.x * ctx->timer.dt * sens->mouse_sens;
|
||||
ctx->output.gimbal.cmd.delta_pit = (float)ctx->input.pc.mouse.y * ctx->timer.dt * sens->mouse_sens * 1.5f;
|
||||
CMD_Behavior_ProcessAll(ctx, &ctx->input, &ctx->last_input, CMD_MODULE_GIMBAL);
|
||||
}
|
||||
|
||||
/* 从PC输入生成射击命令 */
|
||||
static void CMD_PC_BuildShootCmd(CMD_t *ctx) {
|
||||
if (!ctx->input.online[CMD_SRC_PC]) {
|
||||
ctx->output.shoot.cmd.mode = SHOOT_MODE_SAFE;
|
||||
return;
|
||||
}
|
||||
|
||||
ctx->output.shoot.cmd.ready = true;
|
||||
ctx->output.shoot.cmd.firecmd = ctx->input.pc.mouse.l_click;
|
||||
|
||||
CMD_Behavior_ProcessAll(ctx, &ctx->input, &ctx->last_input, CMD_MODULE_SHOOT);
|
||||
|
||||
}
|
||||
|
||||
/* 离线安全模式 */
|
||||
static void CMD_SetOfflineMode(CMD_t *ctx) {
|
||||
ctx->output.chassis.cmd.mode = CHASSIS_MODE_RELAX;
|
||||
ctx->output.gimbal.cmd.mode = GIMBAL_MODE_RELAX;
|
||||
ctx->output.shoot.cmd.mode = SHOOT_MODE_SAFE;
|
||||
}
|
||||
|
||||
/* ========================================================================== */
|
||||
/* 公开API实现 */
|
||||
/* ========================================================================== */
|
||||
|
||||
int8_t CMD_Init(CMD_t *ctx, CMD_Config_t *config) {
|
||||
if (ctx == NULL || config == NULL) {
|
||||
return CMD_ERR_NULL;
|
||||
}
|
||||
|
||||
memset(ctx, 0, sizeof(CMD_t));
|
||||
ctx->config = config;
|
||||
|
||||
/* 初始化适配器 */
|
||||
CMD_Adapter_InitAll();
|
||||
|
||||
/* 初始化行为处理器 */
|
||||
CMD_Behavior_Init();
|
||||
|
||||
return CMD_OK;
|
||||
}
|
||||
|
||||
int8_t CMD_UpdateInput(CMD_t *ctx) {
|
||||
if (ctx == NULL) {
|
||||
return CMD_ERR_NULL;
|
||||
}
|
||||
|
||||
/* 保存上一帧输入 */
|
||||
memcpy(&ctx->last_input, &ctx->input, sizeof(ctx->input));
|
||||
|
||||
/* 更新所有输入源 */
|
||||
for (int i = 0; i < CMD_SRC_NUM; i++) {
|
||||
CMD_Adapter_GetInput((CMD_InputSource_t)i, &ctx->input);
|
||||
}
|
||||
|
||||
return CMD_OK;
|
||||
}
|
||||
typedef void (*CMD_BuildCommandFunc)(CMD_t *cmd);
|
||||
typedef struct {
|
||||
CMD_InputSource_t source;
|
||||
CMD_BuildCommandFunc chassisFunc;
|
||||
CMD_BuildCommandFunc gimbalFunc;
|
||||
CMD_BuildCommandFunc shootFunc;
|
||||
} CMD_SourceHandler_t;
|
||||
|
||||
CMD_SourceHandler_t sourceHandlers[CMD_SRC_NUM] = {
|
||||
{CMD_SRC_RC, CMD_RC_BuildChassisCmd, CMD_RC_BuildGimbalCmd, CMD_RC_BuildShootCmd},
|
||||
{CMD_SRC_PC, CMD_PC_BuildChassisCmd, CMD_PC_BuildGimbalCmd, CMD_PC_BuildShootCmd},
|
||||
{CMD_SRC_NUC, NULL, NULL, NULL},
|
||||
{CMD_SRC_REF, NULL, NULL, NULL},
|
||||
};
|
||||
|
||||
int8_t CMD_Arbitrate(CMD_t *ctx) {
|
||||
if (ctx == NULL) {
|
||||
return CMD_ERR_NULL;
|
||||
}
|
||||
|
||||
/* 自动仲裁:优先级 PC > RC > NUC */
|
||||
CMD_InputSource_t candidates[] = {CMD_SRC_PC, CMD_SRC_RC, CMD_SRC_NUC};
|
||||
const int num_candidates = sizeof(candidates) / sizeof(candidates[0]);
|
||||
|
||||
/* 如果当前输入源仍然在线且有效,保持使用 */
|
||||
if (ctx->active_source < CMD_SRC_NUM &&
|
||||
ctx->active_source != CMD_SRC_REF &&
|
||||
ctx->input.online[ctx->active_source]) {
|
||||
goto seize;
|
||||
}
|
||||
|
||||
/* 否则选择第一个可用的控制输入源 */
|
||||
for (int i = 0; i < num_candidates; i++) {
|
||||
CMD_InputSource_t src = candidates[i];
|
||||
if (ctx->input.online[src]) {
|
||||
ctx->active_source = src;
|
||||
break;
|
||||
}else {
|
||||
ctx->active_source = CMD_SRC_NUM;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
ctx->output.chassis.source = ctx->active_source;
|
||||
ctx->output.gimbal.source = ctx->active_source;
|
||||
ctx->output.shoot.source = ctx->active_source;
|
||||
|
||||
/* 优先级抢占逻辑 */
|
||||
seize:
|
||||
CMD_Behavior_ProcessAll(ctx, &ctx->input, &ctx->last_input, CMD_MODULE_NONE);
|
||||
|
||||
return CMD_OK;
|
||||
}
|
||||
|
||||
int8_t CMD_GenerateCommands(CMD_t *ctx) {
|
||||
if (ctx == NULL) {
|
||||
return CMD_ERR_NULL;
|
||||
}
|
||||
|
||||
/* 更新时间 */
|
||||
uint64_t now_us = BSP_TIME_Get_us();
|
||||
ctx->timer.now = now_us / 1000000.0f;
|
||||
ctx->timer.dt = (now_us - ctx->timer.last_us) / 1000000.0f;
|
||||
ctx->timer.last_us = now_us;
|
||||
|
||||
/* 没有有效输入源 */
|
||||
if (ctx->active_source >= CMD_SRC_NUM) {
|
||||
CMD_SetOfflineMode(ctx);
|
||||
return CMD_ERR_NO_INPUT;
|
||||
}
|
||||
|
||||
sourceHandlers[ctx->output.gimbal.source].gimbalFunc(ctx);
|
||||
sourceHandlers[ctx->output.chassis.source].chassisFunc(ctx);
|
||||
sourceHandlers[ctx->output.shoot.source].shootFunc(ctx);
|
||||
return CMD_OK;
|
||||
}
|
||||
|
||||
int8_t CMD_Update(CMD_t *ctx) {
|
||||
int8_t ret;
|
||||
|
||||
ret = CMD_UpdateInput(ctx);
|
||||
if (ret != CMD_OK) return ret;
|
||||
|
||||
CMD_Arbitrate(ctx);
|
||||
|
||||
ret = CMD_GenerateCommands(ctx);
|
||||
return ret;
|
||||
}
|
||||
172
module/cmd/cmd.h
Normal file
172
module/cmd/cmd.h
Normal file
@ -0,0 +1,172 @@
|
||||
/*
|
||||
* CMD 模块 V2 - 主控制模块
|
||||
* 统一的命令控制接口
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "cmd_types.h"
|
||||
#include "cmd_adapter.h"
|
||||
#include "cmd_behavior.h"
|
||||
|
||||
/* 引入输出模块的命令类型 */
|
||||
#include "module/chassis.h"
|
||||
#include "module/gimbal.h"
|
||||
#include "module/shoot.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ========================================================================== */
|
||||
/* 输出命令结构 */
|
||||
/* ========================================================================== */
|
||||
|
||||
/* 每个模块的输出包含源信息和命令 */
|
||||
typedef struct {
|
||||
CMD_InputSource_t source;
|
||||
Chassis_CMD_t cmd;
|
||||
} CMD_ChassisOutput_t;
|
||||
|
||||
typedef struct {
|
||||
CMD_InputSource_t source;
|
||||
Gimbal_CMD_t cmd;
|
||||
} CMD_GimbalOutput_t;
|
||||
|
||||
typedef struct {
|
||||
CMD_InputSource_t source;
|
||||
Shoot_CMD_t cmd;
|
||||
} CMD_ShootOutput_t;
|
||||
|
||||
/* ========================================================================== */
|
||||
/* 配置结构 */
|
||||
/* ========================================================================== */
|
||||
|
||||
/* 灵敏度配置 */
|
||||
typedef struct {
|
||||
float mouse_sens; /* 鼠标灵敏度 */
|
||||
float move_sens; /* 移动灵敏度 */
|
||||
float move_fast_mult; /* 快速移动倍率 */
|
||||
float move_slow_mult; /* 慢速移动倍率 */
|
||||
} CMD_Sensitivity_t;
|
||||
|
||||
/* RC模式映射配置 - 定义开关位置到模式的映射 */
|
||||
typedef struct {
|
||||
/* 左拨杆映射 - 底盘模式 */
|
||||
Chassis_Mode_t sw_left_up;
|
||||
Chassis_Mode_t sw_left_mid;
|
||||
Chassis_Mode_t sw_left_down;
|
||||
|
||||
/* 右拨杆映射 - 云台/射击模式 */
|
||||
Gimbal_Mode_t gimbal_sw_up;
|
||||
Gimbal_Mode_t gimbal_sw_mid;
|
||||
Gimbal_Mode_t gimbal_sw_down;
|
||||
} CMD_RCModeMap_t;
|
||||
|
||||
/* 整体配置 */
|
||||
typedef struct {
|
||||
/* 输入源优先级,索引越小优先级越高 */
|
||||
CMD_InputSource_t source_priority[CMD_SRC_NUM];
|
||||
|
||||
/* 灵敏度设置 */
|
||||
CMD_Sensitivity_t sensitivity;
|
||||
|
||||
/* RC模式映射 */
|
||||
CMD_RCModeMap_t rc_mode_map;
|
||||
|
||||
} CMD_Config_t;
|
||||
|
||||
/* ========================================================================== */
|
||||
/* 主控制上下文 */
|
||||
/* ========================================================================== */
|
||||
|
||||
typedef struct {
|
||||
float now;
|
||||
float dt;
|
||||
uint32_t last_us;
|
||||
} CMD_Timer_t;
|
||||
|
||||
typedef struct CMD_Context {
|
||||
/* 配置 */
|
||||
CMD_Config_t *config;
|
||||
|
||||
/* 时间 */
|
||||
CMD_Timer_t timer;
|
||||
|
||||
/* 当前帧和上一帧的原始输入 */
|
||||
CMD_RawInput_t input;
|
||||
CMD_RawInput_t last_input;
|
||||
|
||||
/* 仲裁后的活跃输入源 */
|
||||
CMD_InputSource_t active_source;
|
||||
|
||||
/* 输出 */
|
||||
struct {
|
||||
CMD_ChassisOutput_t chassis;
|
||||
CMD_GimbalOutput_t gimbal;
|
||||
CMD_ShootOutput_t shoot;
|
||||
} output;
|
||||
} CMD_t;
|
||||
|
||||
/* ========================================================================== */
|
||||
/* 主API接口 */
|
||||
/* ========================================================================== */
|
||||
|
||||
/**
|
||||
* @brief 初始化CMD模块
|
||||
* @param ctx CMD上下文
|
||||
* @param config 配置指针
|
||||
* @return CMD_OK成功,其他失败
|
||||
*/
|
||||
int8_t CMD_Init(CMD_t *ctx, CMD_Config_t *config);
|
||||
|
||||
/**
|
||||
* @brief 更新所有输入源的数据
|
||||
* @param ctx CMD上下文
|
||||
* @return CMD_OK成功
|
||||
*/
|
||||
int8_t CMD_UpdateInput(CMD_t *ctx);
|
||||
|
||||
/**
|
||||
* @brief 执行仲裁,决定使用哪个输入源
|
||||
* @param ctx CMD上下文
|
||||
* @return 选中的输入源
|
||||
*/
|
||||
int8_t CMD_Arbitrate(CMD_t *ctx);
|
||||
|
||||
/**
|
||||
* @brief 生成所有模块的控制命令
|
||||
* @param ctx CMD上下文
|
||||
* @return CMD_OK成功
|
||||
*/
|
||||
int8_t CMD_GenerateCommands(CMD_t *ctx);
|
||||
|
||||
/**
|
||||
* @brief 一键更新(包含UpdateInput + Arbitrate + GenerateCommands)
|
||||
* @param ctx CMD上下文
|
||||
* @return CMD_OK成功
|
||||
*/
|
||||
int8_t CMD_Update(CMD_t *ctx);
|
||||
|
||||
/* ========================================================================== */
|
||||
/* 输出获取接口 */
|
||||
/* ========================================================================== */
|
||||
|
||||
/* 获取底盘命令 */
|
||||
static inline Chassis_CMD_t* CMD_GetChassisCmd(CMD_t *ctx) {
|
||||
return &ctx->output.chassis.cmd;
|
||||
}
|
||||
|
||||
/* 获取云台命令 */
|
||||
static inline Gimbal_CMD_t* CMD_GetGimbalCmd(CMD_t *ctx) {
|
||||
return &ctx->output.gimbal.cmd;
|
||||
}
|
||||
|
||||
/* 获取射击命令 */
|
||||
static inline Shoot_CMD_t* CMD_GetShootCmd(CMD_t *ctx) {
|
||||
return &ctx->output.shoot.cmd;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
184
module/cmd/cmd_adapter.c
Normal file
184
module/cmd/cmd_adapter.c
Normal file
@ -0,0 +1,184 @@
|
||||
/*
|
||||
* CMD 模块 V2 - 输入适配器实现
|
||||
*/
|
||||
#include "cmd_adapter.h"
|
||||
#include <string.h>
|
||||
|
||||
/* ========================================================================== */
|
||||
/* 适配器存储 */
|
||||
/* ========================================================================== */
|
||||
// static CMD_InputAdapter_t *g_adapters[CMD_SRC_NUM] = {0};
|
||||
CMD_InputAdapter_t *g_adapters[CMD_SRC_NUM] = {0};
|
||||
/* ========================================================================== */
|
||||
/* DR16 抽象实现 */
|
||||
/* ========================================================================== */
|
||||
#if CMD_RC_DEVICE_TYPE == 0
|
||||
|
||||
int8_t CMD_DR16_Init(void *data) {
|
||||
DR16_t *dr16 = (DR16_t *)data;
|
||||
return DR16_Init(dr16);
|
||||
}
|
||||
|
||||
int8_t CMD_DR16_RC_GetInput(void *data, CMD_RawInput_t *output) {
|
||||
DR16_t *dr16 = (DR16_t *)data;
|
||||
|
||||
memset(&output->rc, 0, sizeof(CMD_RawInput_RC_t));
|
||||
|
||||
output->online[CMD_SRC_RC] = dr16->header.online;
|
||||
|
||||
/* 遥控器摇杆映射 */
|
||||
output->rc.joy_left.x = dr16->data.rc.ch_l_x;
|
||||
output->rc.joy_left.y = dr16->data.rc.ch_l_y;
|
||||
output->rc.joy_right.x = dr16->data.rc.ch_r_x;
|
||||
output->rc.joy_right.y = dr16->data.rc.ch_r_y;
|
||||
|
||||
/* 拨杆映射 */
|
||||
switch (dr16->data.rc.sw_l) {
|
||||
case DR16_SW_UP: output->rc.sw[0] = CMD_SW_UP; break;
|
||||
case DR16_SW_MID: output->rc.sw[0] = CMD_SW_MID; break;
|
||||
case DR16_SW_DOWN: output->rc.sw[0] = CMD_SW_DOWN; break;
|
||||
default: output->rc.sw[0] = CMD_SW_ERR; break;
|
||||
}
|
||||
switch (dr16->data.rc.sw_r) {
|
||||
case DR16_SW_UP: output->rc.sw[1] = CMD_SW_UP; break;
|
||||
case DR16_SW_MID: output->rc.sw[1] = CMD_SW_MID; break;
|
||||
case DR16_SW_DOWN: output->rc.sw[1] = CMD_SW_DOWN; break;
|
||||
default: output->rc.sw[1] = CMD_SW_ERR; break;
|
||||
}
|
||||
|
||||
/* 拨轮映射 */
|
||||
output->rc.dial = dr16->data.rc.ch_res;
|
||||
|
||||
return CMD_OK;
|
||||
}
|
||||
|
||||
int8_t CMD_DR16_PC_GetInput(void *data, CMD_RawInput_t *output) {
|
||||
DR16_t *dr16 = (DR16_t *)data;
|
||||
|
||||
memset(&output->pc, 0, sizeof(CMD_RawInput_PC_t));
|
||||
|
||||
output->online[CMD_SRC_PC] = dr16->header.online;
|
||||
|
||||
/* PC端鼠标映射 */
|
||||
output->pc.mouse.x = dr16->data.pc.mouse.x;
|
||||
output->pc.mouse.y = dr16->data.pc.mouse.y;
|
||||
output->pc.mouse.l_click = dr16->data.pc.mouse.l_click;
|
||||
output->pc.mouse.r_click = dr16->data.pc.mouse.r_click;
|
||||
|
||||
/* 键盘映射 */
|
||||
output->pc.keyboard.bitmap = dr16->raw_data.key;
|
||||
|
||||
return CMD_OK;
|
||||
}
|
||||
|
||||
bool CMD_DR16_IsOnline(void *data) {
|
||||
DR16_t *dr16 = (DR16_t *)data;
|
||||
return dr16->header.online;
|
||||
}
|
||||
extern DR16_t cmd_dr16;
|
||||
/* 定义适配器实例 */
|
||||
CMD_DEFINE_ADAPTER(DR16_RC, cmd_dr16, CMD_SRC_RC, CMD_DR16_Init, CMD_DR16_RC_GetInput, CMD_DR16_IsOnline)
|
||||
CMD_DEFINE_ADAPTER(DR16_PC, cmd_dr16, CMD_SRC_PC, CMD_DR16_Init, CMD_DR16_PC_GetInput, CMD_DR16_IsOnline)
|
||||
|
||||
#endif /* CMD_RC_DEVICE_TYPE == 0 */
|
||||
|
||||
/* ========================================================================== */
|
||||
/* AT9S 抽象实现 (示例框架) */
|
||||
/* ========================================================================== */
|
||||
#if CMD_RC_DEVICE_TYPE == 1
|
||||
|
||||
int8_t CMD_AT9S_Init(void *data) {
|
||||
AT9S_t *at9s = (AT9S_t *)data;
|
||||
return AT9S_Init(at9s);
|
||||
}
|
||||
|
||||
int8_t CMD_AT9S_GetInput(void *data, CMD_RawInput_t *output) {
|
||||
AT9S_t *at9s = (AT9S_t *)data;
|
||||
|
||||
memset(output, 0, sizeof(CMD_RawInput_RC_t));
|
||||
|
||||
output->online[CMD_SRC_RC] = at9s->header.online;
|
||||
|
||||
/* TODO: 按照AT9S的数据格式进行映射 */
|
||||
output->joy_left.x = at9s->data.rc.ch_l_x;
|
||||
output->joy_left.y = at9s->data.rc.ch_l_y;
|
||||
output->joy_right.x = at9s->data.rc.ch_r_x;
|
||||
output->joy_right.y = at9s->data.rc.ch_r_y;
|
||||
|
||||
/* 拨杆映射需要根据AT9S的实际定义 */
|
||||
|
||||
return CMD_OK;
|
||||
}
|
||||
|
||||
bool CMD_AT9S_IsOnline(void *data) {
|
||||
AT9S_t *at9s = (AT9S_t *)data;
|
||||
return at9s->header.online;
|
||||
}
|
||||
|
||||
CMD_DEFINE_ADAPTER(AT9S, at9s, CMD_SRC_RC, CMD_AT9S_Init, CMD_AT9S_GetInput, CMD_AT9S_IsOnline)
|
||||
|
||||
#endif /* CMD_RC_DEVICE_TYPE == 1 */
|
||||
|
||||
/* ========================================================================== */
|
||||
/* 适配器管理实现 */
|
||||
/* ========================================================================== */
|
||||
|
||||
int8_t CMD_Adapter_Register(CMD_InputAdapter_t *adapter) {
|
||||
if (adapter == NULL || adapter->source >= CMD_SRC_NUM) {
|
||||
return CMD_ERR_NULL;
|
||||
}
|
||||
g_adapters[adapter->source] = adapter;
|
||||
return CMD_OK;
|
||||
}
|
||||
|
||||
int8_t CMD_Adapter_InitAll(void) {
|
||||
/* 注册编译时选择的RC设备适配器 */
|
||||
#if CMD_RC_DEVICE_TYPE == 0
|
||||
/* DR16 支持 RC 和 PC 输入 */
|
||||
CMD_Adapter_Register(&g_adapter_DR16_RC);
|
||||
CMD_Adapter_Register(&g_adapter_DR16_PC);
|
||||
#elif CMD_RC_DEVICE_TYPE == 1
|
||||
/* AT9S 目前只支持 RC 输入 */
|
||||
CMD_Adapter_Register(&g_adapter_AT9S);
|
||||
#endif
|
||||
|
||||
/* 注册NUC适配器 */
|
||||
|
||||
/* 注册REF适配器 */
|
||||
|
||||
/* 初始化所有已注册的适配器 */
|
||||
for (int i = 0; i < CMD_SRC_NUM; i++) {
|
||||
if (g_adapters[i] != NULL && g_adapters[i]->init != NULL) {
|
||||
g_adapters[i]->init(g_adapters[i]->device_data);
|
||||
}
|
||||
}
|
||||
|
||||
return CMD_OK;
|
||||
}
|
||||
|
||||
int8_t CMD_Adapter_GetInput(CMD_InputSource_t source, CMD_RawInput_t *output) {
|
||||
if (source >= CMD_SRC_NUM || output == NULL) {
|
||||
return CMD_ERR_NULL;
|
||||
}
|
||||
|
||||
CMD_InputAdapter_t *adapter = g_adapters[source];
|
||||
if (adapter == NULL || adapter->get_input == NULL) {
|
||||
output->online[adapter->source] = false;
|
||||
return CMD_ERR_NO_INPUT;
|
||||
}
|
||||
|
||||
return adapter->get_input(adapter->device_data, output);
|
||||
}
|
||||
|
||||
bool CMD_Adapter_IsOnline(CMD_InputSource_t source) {
|
||||
if (source >= CMD_SRC_NUM) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CMD_InputAdapter_t *adapter = g_adapters[source];
|
||||
if (adapter == NULL || adapter->is_online == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return adapter->is_online(adapter->device_data);
|
||||
}
|
||||
111
module/cmd/cmd_adapter.h
Normal file
111
module/cmd/cmd_adapter.h
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* CMD 模块 V2 - 输入适配器接口
|
||||
* 定义设备到统一输入结构的转换接口
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "cmd_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ========================================================================== */
|
||||
/* 适配器接口定义 */
|
||||
/* ========================================================================== */
|
||||
|
||||
/* 适配器操作函数指针类型 */
|
||||
typedef int8_t (*CMD_AdapterInitFunc)(void *device_data);
|
||||
typedef int8_t (*CMD_AdapterGetInputFunc)(void *device_data, CMD_RawInput_t *output);
|
||||
typedef bool (*CMD_AdapterIsOnlineFunc)(void *device_data);
|
||||
|
||||
/* 适配器描述结构 */
|
||||
typedef struct {
|
||||
const char *name; /* 适配器名称 */
|
||||
CMD_InputSource_t source; /* 对应的输入源 */
|
||||
void *device_data; /* 设备数据指针 */
|
||||
CMD_AdapterInitFunc init; /* 初始化函数 */
|
||||
CMD_AdapterGetInputFunc get_input; /* 获取输入函数 */
|
||||
CMD_AdapterIsOnlineFunc is_online; /* 在线检测函数 */
|
||||
} CMD_InputAdapter_t;
|
||||
|
||||
/* ========================================================================== */
|
||||
/* 适配器注册宏 */
|
||||
/* ========================================================================== */
|
||||
|
||||
/*
|
||||
* 声明适配器
|
||||
* 使用示例:
|
||||
* CMD_DECLARE_ADAPTER(DR16, dr16, DR16_t)
|
||||
*
|
||||
* 会生成:
|
||||
* - extern DR16_t dr16; // 设备实例声明
|
||||
* - int8_t CMD_DR16_Init(void *data);
|
||||
* - int8_t CMD_DR16_GetInput(void *data, CMD_RawInput_t *output);
|
||||
* - bool CMD_DR16_IsOnline(void *data);
|
||||
*/
|
||||
#define CMD_DECLARE_ADAPTER(NAME, var, TYPE) \
|
||||
extern TYPE var; \
|
||||
int8_t CMD_##NAME##_Init(void *data); \
|
||||
int8_t CMD_##NAME##_GetInput(void *data, CMD_RawInput_t *output); \
|
||||
bool CMD_##NAME##_IsOnline(void *data);
|
||||
|
||||
/*
|
||||
* 定义适配器实例
|
||||
* 使用示例:
|
||||
* CMD_DEFINE_ADAPTER(DR16_RC, dr16, CMD_SRC_RC, CMD_DR16_Init, CMD_DR16_RC_GetInput, CMD_DR16_RC_IsOnline)
|
||||
*/
|
||||
#define CMD_DEFINE_ADAPTER(NAME, var, source_enum, init_func, get_func, online_func) \
|
||||
static CMD_InputAdapter_t g_adapter_##NAME = { \
|
||||
.name = #NAME, \
|
||||
.source = source_enum, \
|
||||
.device_data = (void*)&var, \
|
||||
.init = init_func, \
|
||||
.get_input = get_func, \
|
||||
.is_online = online_func, \
|
||||
};
|
||||
|
||||
/* ========================================================================== */
|
||||
/* RC设备适配器配置 */
|
||||
/* ========================================================================== */
|
||||
|
||||
/* 选择使用的RC设备 - 只需修改这里 */
|
||||
#define CMD_RC_DEVICE_TYPE 0 /* 0:DR16, 1:AT9S, 2:VT13 */
|
||||
|
||||
#if CMD_RC_DEVICE_TYPE == 0
|
||||
#include "device/dr16.h"
|
||||
CMD_DECLARE_ADAPTER(DR16_RC, dr16, DR16_t)
|
||||
CMD_DECLARE_ADAPTER(DR16_PC, dr16, DR16_t)
|
||||
#define CMD_RC_ADAPTER_NAME DR16
|
||||
#define CMD_RC_ADAPTER_VAR dr16
|
||||
#elif CMD_RC_DEVICE_TYPE == 1
|
||||
#include "device/at9s_pro.h"
|
||||
CMD_DECLARE_ADAPTER(AT9S, at9s, AT9S_t)
|
||||
#define CMD_RC_ADAPTER_NAME AT9S
|
||||
#define CMD_RC_ADAPTER_VAR at9s
|
||||
#elif CMD_RC_DEVICE_TYPE == 2
|
||||
#include "device/vt13.h"
|
||||
CMD_DECLARE_ADAPTER(VT13, vt13, VT13_t)
|
||||
#define CMD_RC_ADAPTER_NAME VT13
|
||||
#define CMD_RC_ADAPTER_VAR vt13
|
||||
#endif
|
||||
|
||||
/* ========================================================================== */
|
||||
/* 适配器管理接口 */
|
||||
/* ========================================================================== */
|
||||
|
||||
/* 初始化所有适配器 */
|
||||
int8_t CMD_Adapter_InitAll(void);
|
||||
|
||||
/* 获取指定输入源的原始输入 */
|
||||
int8_t CMD_Adapter_GetInput(CMD_InputSource_t source, CMD_RawInput_t *output);
|
||||
|
||||
/* 检查输入源是否在线 */
|
||||
bool CMD_Adapter_IsOnline(CMD_InputSource_t source);
|
||||
|
||||
/* 注册适配器 (运行时注册,可选) */
|
||||
int8_t CMD_Adapter_Register(CMD_InputAdapter_t *adapter);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
172
module/cmd/cmd_behavior.c
Normal file
172
module/cmd/cmd_behavior.c
Normal file
@ -0,0 +1,172 @@
|
||||
/*
|
||||
* CMD 模块 V2 - 行为处理器实现
|
||||
*/
|
||||
#include "cmd_behavior.h"
|
||||
#include "cmd.h"
|
||||
#include "module/gimbal.h"
|
||||
#include <string.h>
|
||||
|
||||
/* ========================================================================== */
|
||||
/* 行为回调函数 */
|
||||
/* ========================================================================== */
|
||||
|
||||
/* 行为处理函数实现 */
|
||||
int8_t CMD_Behavior_Handle_FORE(CMD_t *ctx) {
|
||||
ctx->output.chassis.cmd.ctrl_vec.vy += ctx->config->sensitivity.move_sens;
|
||||
return CMD_OK;
|
||||
}
|
||||
|
||||
int8_t CMD_Behavior_Handle_BACK(CMD_t *ctx) {
|
||||
ctx->output.chassis.cmd.ctrl_vec.vy -= ctx->config->sensitivity.move_sens;
|
||||
return CMD_OK;
|
||||
}
|
||||
|
||||
int8_t CMD_Behavior_Handle_LEFT(CMD_t *ctx) {
|
||||
ctx->output.chassis.cmd.ctrl_vec.vx -= ctx->config->sensitivity.move_sens;
|
||||
return CMD_OK;
|
||||
}
|
||||
|
||||
int8_t CMD_Behavior_Handle_RIGHT(CMD_t *ctx) {
|
||||
ctx->output.chassis.cmd.ctrl_vec.vx += ctx->config->sensitivity.move_sens;
|
||||
return CMD_OK;
|
||||
}
|
||||
|
||||
int8_t CMD_Behavior_Handle_ACCELERATE(CMD_t *ctx) {
|
||||
ctx->output.chassis.cmd.ctrl_vec.vx *= ctx->config->sensitivity.move_fast_mult;
|
||||
ctx->output.chassis.cmd.ctrl_vec.vy *= ctx->config->sensitivity.move_fast_mult;
|
||||
return CMD_OK;
|
||||
}
|
||||
|
||||
int8_t CMD_Behavior_Handle_DECELERATE(CMD_t *ctx) {
|
||||
ctx->output.chassis.cmd.ctrl_vec.vx *= ctx->config->sensitivity.move_slow_mult;
|
||||
ctx->output.chassis.cmd.ctrl_vec.vy *= ctx->config->sensitivity.move_slow_mult;
|
||||
return CMD_OK;
|
||||
}
|
||||
|
||||
int8_t CMD_Behavior_Handle_FIRE(CMD_t *ctx) {
|
||||
ctx->output.shoot.cmd.firecmd = true;
|
||||
return CMD_OK;
|
||||
}
|
||||
|
||||
int8_t CMD_Behavior_Handle_FIRE_MODE(CMD_t *ctx) {
|
||||
ctx->output.shoot.cmd.mode = (ctx->output.shoot.cmd.mode + 1) % SHOOT_MODE_NUM;
|
||||
return CMD_OK;
|
||||
}
|
||||
|
||||
int8_t CMD_Behavior_Handle_ROTOR(CMD_t *ctx) {
|
||||
ctx->output.chassis.cmd.mode = CHASSIS_MODE_ROTOR;
|
||||
ctx->output.chassis.cmd.mode_rotor = ROTOR_MODE_RAND;
|
||||
ctx->output.gimbal.cmd.mode = GIMBAL_MODE_RELATIVE;
|
||||
return CMD_OK;
|
||||
}
|
||||
|
||||
int8_t CMD_Behavior_Handle_AUTOAIM(CMD_t *ctx) {
|
||||
/* TODO: 自瞄模式切换 */
|
||||
return CMD_OK;
|
||||
}
|
||||
|
||||
int8_t CMD_Behavior_Handle_CHECKSOURCERCPC(CMD_t *ctx) {
|
||||
/* TODO: 切换RC和PC输入源 */
|
||||
if (ctx->active_source == CMD_SRC_PC) {
|
||||
ctx->active_source = CMD_SRC_RC;
|
||||
ctx->output.chassis.source = CMD_SRC_RC;
|
||||
ctx->output.gimbal.source = CMD_SRC_RC;
|
||||
ctx->output.shoot.source = CMD_SRC_RC;
|
||||
} else if(ctx->active_source == CMD_SRC_RC) {
|
||||
ctx->active_source = CMD_SRC_PC;
|
||||
ctx->output.chassis.source = CMD_SRC_PC;
|
||||
ctx->output.gimbal.source = CMD_SRC_PC;
|
||||
ctx->output.shoot.source = CMD_SRC_PC;
|
||||
}
|
||||
return CMD_OK;
|
||||
}
|
||||
|
||||
/* 行为配置表 - 由宏生成 */
|
||||
static const CMD_BehaviorConfig_t g_behavior_configs[] = {
|
||||
CMD_BEHAVIOR_TABLE(BUILD_BEHAVIOR_CONFIG)
|
||||
};
|
||||
|
||||
/* ========================================================================== */
|
||||
/* API实现 */
|
||||
/* ========================================================================== */
|
||||
|
||||
int8_t CMD_Behavior_Init(void) {
|
||||
/* 当前静态配置,无需初始化 */
|
||||
return CMD_OK;
|
||||
}
|
||||
|
||||
bool CMD_Behavior_IsTriggered(const CMD_RawInput_t *current,
|
||||
const CMD_RawInput_t *last,
|
||||
const CMD_BehaviorConfig_t *config) {
|
||||
if (config == NULL || current == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool now_pressed = false;
|
||||
bool last_pressed = false;
|
||||
|
||||
// 鼠标特殊按键处理
|
||||
if (config->key == (CMD_KEY_L_CLICK)) {
|
||||
now_pressed = current->pc.mouse.l_click;
|
||||
last_pressed = last ? last->pc.mouse.l_click : false;
|
||||
} else if (config->key == (CMD_KEY_R_CLICK)) {
|
||||
now_pressed = current->pc.mouse.r_click;
|
||||
last_pressed = last ? last->pc.mouse.r_click : false;
|
||||
} else if (config->key == (CMD_KEY_M_CLICK)) {
|
||||
now_pressed = current->pc.mouse.m_click;
|
||||
last_pressed = last ? last->pc.mouse.m_click : false;
|
||||
} else if (config->key == 0) {
|
||||
return false;
|
||||
} else {
|
||||
// 多按键组合检测
|
||||
now_pressed = ((current->pc.keyboard.bitmap & config->key) == config->key);
|
||||
last_pressed = last ? ((last->pc.keyboard.bitmap & config->key) == config->key) : false;
|
||||
}
|
||||
|
||||
switch (config->trigger) {
|
||||
case CMD_ACTIVE_PRESSED:
|
||||
return now_pressed;
|
||||
case CMD_ACTIVE_RISING_EDGE:
|
||||
return now_pressed && !last_pressed;
|
||||
case CMD_ACTIVE_FALLING_EDGE:
|
||||
return !now_pressed && last_pressed;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int8_t CMD_Behavior_ProcessAll(CMD_t *ctx,
|
||||
const CMD_RawInput_t *current,
|
||||
const CMD_RawInput_t *last,
|
||||
CMD_ModuleMask_t active_modules) {
|
||||
if (ctx == NULL || current == NULL) {
|
||||
return CMD_ERR_NULL;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < BEHAVIOR_CONFIG_COUNT; i++) {
|
||||
const CMD_BehaviorConfig_t *config = &g_behavior_configs[i];
|
||||
|
||||
/* 过滤模块掩码 */
|
||||
if ((config->module_mask & active_modules) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* 检查是否触发 */
|
||||
if (CMD_Behavior_IsTriggered(current, last, config)) {
|
||||
if (config->handler != NULL) {
|
||||
config->handler(ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return CMD_OK;
|
||||
}
|
||||
|
||||
const CMD_BehaviorConfig_t* CMD_Behavior_GetConfig(CMD_Behavior_t behavior) {
|
||||
for (size_t i = 0; i < BEHAVIOR_CONFIG_COUNT; i++) {
|
||||
if (g_behavior_configs[i].behavior == behavior) {
|
||||
return &g_behavior_configs[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
69
module/cmd/cmd_behavior.h
Normal file
69
module/cmd/cmd_behavior.h
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* CMD 模块 V2 - 行为处理器
|
||||
* 实现PC端按键到行为的映射和处理
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "cmd_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ========================================================================== */
|
||||
/* 行为处理器接口 */
|
||||
/* ========================================================================== */
|
||||
|
||||
/* 行为处理函数类型 */
|
||||
struct CMD_Context; /* 前向声明 */
|
||||
typedef int8_t (*CMD_BehaviorHandler)(struct CMD_Context *ctx);
|
||||
|
||||
/* 行为配置项 */
|
||||
typedef struct {
|
||||
CMD_Behavior_t behavior; /* 行为枚举 */
|
||||
uint32_t key; /* 绑定的按键 */
|
||||
CMD_TriggerType_t trigger; /* 触发类型 */
|
||||
CMD_ModuleMask_t module_mask; /* 影响的模块 */
|
||||
CMD_BehaviorHandler handler; /* 处理函数 */
|
||||
} CMD_BehaviorConfig_t;
|
||||
|
||||
/* ========================================================================== */
|
||||
/* 行为表生成宏 */
|
||||
/* ========================================================================== */
|
||||
|
||||
/* 从宏表生成配置数组 */
|
||||
#define BUILD_BEHAVIOR_CONFIG(name, key, trigger, mask) \
|
||||
{ CMD_BEHAVIOR_##name, key, trigger, mask, CMD_Behavior_Handle_##name },
|
||||
|
||||
/* 声明所有行为处理函数 */
|
||||
#define DECLARE_BEHAVIOR_HANDLER(name, key, trigger, mask) \
|
||||
int8_t CMD_Behavior_Handle_##name(struct CMD_Context *ctx);
|
||||
|
||||
/* 展开声明 */
|
||||
CMD_BEHAVIOR_TABLE(DECLARE_BEHAVIOR_HANDLER)
|
||||
#undef DECLARE_BEHAVIOR_HANDLER
|
||||
|
||||
/* ========================================================================== */
|
||||
/* 行为处理器API */
|
||||
/* ========================================================================== */
|
||||
|
||||
/* 初始化行为处理器 */
|
||||
int8_t CMD_Behavior_Init(void);
|
||||
|
||||
/* 检查行为是否被触发 */
|
||||
bool CMD_Behavior_IsTriggered(const CMD_RawInput_t *current,
|
||||
const CMD_RawInput_t *last,
|
||||
const CMD_BehaviorConfig_t *config);
|
||||
|
||||
/* 处理所有触发的行为 */
|
||||
int8_t CMD_Behavior_ProcessAll(struct CMD_Context *ctx,
|
||||
const CMD_RawInput_t *current,
|
||||
const CMD_RawInput_t *last,
|
||||
CMD_ModuleMask_t active_modules);
|
||||
|
||||
/* 获取行为配置 */
|
||||
const CMD_BehaviorConfig_t* CMD_Behavior_GetConfig(CMD_Behavior_t behavior);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
144
module/cmd/cmd_example.c
Normal file
144
module/cmd/cmd_example.c
Normal file
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* CMD 模块 V2 - 使用示例和配置模板
|
||||
*
|
||||
* 本文件展示如何配置和使用新的CMD模块
|
||||
*/
|
||||
#include "cmd.h"
|
||||
|
||||
/* ========================================================================== */
|
||||
/* 配置示例 */
|
||||
/* ========================================================================== */
|
||||
|
||||
/* 默认配置 */
|
||||
// static CMD_Config_t g_cmd_config = {
|
||||
// /* 灵敏度设置 */
|
||||
// .sensitivity = {
|
||||
// .mouse_sens = 0.8f,
|
||||
// .move_sens = 1.0f,
|
||||
// .move_fast_mult = 1.5f,
|
||||
// .move_slow_mult = 0.5f,
|
||||
// },
|
||||
|
||||
// /* RC拨杆模式映射 */
|
||||
// .rc_mode_map = {
|
||||
// /* 左拨杆控制底盘模式 */
|
||||
// .sw_left_up = CHASSIS_MODE_BREAK,
|
||||
// .sw_left_mid = CHASSIS_MODE_FOLLOW_GIMBAL,
|
||||
// .sw_left_down = CHASSIS_MODE_ROTOR,
|
||||
|
||||
// /* 用于云台模式 */
|
||||
// .gimbal_sw_up = GIMBAL_MODE_ABSOLUTE,
|
||||
// .gimbal_sw_mid = GIMBAL_MODE_ABSOLUTE,
|
||||
// .gimbal_sw_down = GIMBAL_MODE_RELATIVE,
|
||||
// },
|
||||
|
||||
// };
|
||||
|
||||
// /* CMD上下文 */
|
||||
// static CMD_t g_cmd_ctx;
|
||||
|
||||
/* ========================================================================== */
|
||||
/* 任务示例 */
|
||||
/* ========================================================================== */
|
||||
|
||||
/*
|
||||
* 初始化示例
|
||||
*/
|
||||
// void Example_CMD_Init(void) {
|
||||
// CMD_Init(&g_cmd_ctx, &g_cmd_config);
|
||||
// }
|
||||
|
||||
// /*
|
||||
// * 任务循环示例
|
||||
// */
|
||||
// void Example_CMD_Task(void) {
|
||||
// /* 一键更新 */
|
||||
// CMD_Update(&g_cmd_ctx);
|
||||
|
||||
// /* 获取命令发送到各模块 */
|
||||
// Chassis_CMD_t *chassis_cmd = CMD_GetChassisCmd(&g_cmd_ctx);
|
||||
// Gimbal_CMD_t *gimbal_cmd = CMD_GetGimbalCmd(&g_cmd_ctx);
|
||||
// Shoot_CMD_t *shoot_cmd = CMD_GetShootCmd(&g_cmd_ctx);
|
||||
|
||||
// /* 使用命令... */
|
||||
// (void)chassis_cmd;
|
||||
// (void)gimbal_cmd;
|
||||
// (void)shoot_cmd;
|
||||
// }
|
||||
|
||||
/* ========================================================================== */
|
||||
/* 架构说明 */
|
||||
/* ========================================================================== */
|
||||
|
||||
/*
|
||||
* ## 新架构优势
|
||||
*
|
||||
* ### 1. 统一的输入抽象层 (CMD_RawInput_t)
|
||||
* - 所有设备(DR16/AT9S/VT13等)都转换成相同格式
|
||||
* - 上层代码无需关心具体设备类型
|
||||
* - 添加新设备只需实现适配器,不改动主逻辑
|
||||
*
|
||||
* ### 2. 适配器模式
|
||||
* - 每个设备一个适配器文件
|
||||
* - 实现 Init, GetInput, IsOnline 三个函数
|
||||
* - 通过宏选择编译哪个适配器
|
||||
*
|
||||
* ### 3. X-Macro配置表
|
||||
* - CMD_INPUT_SOURCE_TABLE: 配置输入源
|
||||
* - CMD_OUTPUT_MODULE_TABLE: 配置输出模块
|
||||
* - CMD_BEHAVIOR_TABLE: 配置按键行为映射
|
||||
* - 编译时生成枚举、配置数组、处理函数
|
||||
*
|
||||
* ### 4. 行为驱动设计
|
||||
* - 行为与按键解耦
|
||||
* - 运行时可修改映射
|
||||
* - 支持边沿触发和持续触发
|
||||
*
|
||||
* ### 5. 清晰的分层
|
||||
*
|
||||
* ┌──────────────────────────────────────┐
|
||||
* │ 应用层 (cmd.c) │
|
||||
* │ - CMD_Update() │
|
||||
* │ - 仲裁、命令生成 │
|
||||
* └──────────────┬───────────────────────┘
|
||||
* │
|
||||
* ┌──────────────▼───────────────────────┐
|
||||
* │ 行为处理层 (cmd_behavior.c) │
|
||||
* │ - 按键触发检测 │
|
||||
* │ - 行为函数调用 │
|
||||
* └──────────────┬───────────────────────┘
|
||||
* │
|
||||
* ┌──────────────▼──────────────────────────┐
|
||||
* │ 抽象输入层 (cmd_types.h) │
|
||||
* │ - 多输入源操作同一CMD_RawInput_t不同分区 │
|
||||
* │ - 统一的摇杆、开关、键鼠结构 │
|
||||
* └──────────────┬──────────────────────────┘
|
||||
* │
|
||||
* ┌──────────────▼───────────────────────┐
|
||||
* │ 适配器层 (cmd_adapter.c) │
|
||||
* │ - DR16_Adapter │
|
||||
* │ - AT9S_Adapter │
|
||||
* │ - 设备数据 → CMD_RawInput_t │
|
||||
* └──────────────────────────────────────┘
|
||||
*
|
||||
* ## 扩展指南
|
||||
*
|
||||
* ### 添加新遥控器设备
|
||||
* 1. 在 cmd_adapter.h 中添加宏定义选项
|
||||
* 2. 在 cmd_adapter.c 中实现三个适配器函数
|
||||
* 3. 修改 CMD_RC_DEVICE_TYPE 宏选择新设备
|
||||
*
|
||||
* ### 添加新输入源(如自定义协议)
|
||||
* 1. 在 CMD_INPUT_SOURCE_TABLE 添加条目
|
||||
* 2. 实现对应的适配器
|
||||
* 3. 在 CMD_GenerateCommands 添加处理分支
|
||||
*
|
||||
* ### 添加新行为
|
||||
* 1. 在 CMD_BEHAVIOR_TABLE 添加条目,并修正BEHAVIOR_CONFIG_COUNT
|
||||
* 2. 实现 CMD_Behavior_Handle_XXX 函数
|
||||
*
|
||||
* ### 添加新输出模块
|
||||
* 1. 在 CMD_OUTPUT_MODULE_TABLE 添加条目
|
||||
* 2. 在 CMD_t 中添加输出成员
|
||||
* 3. 实现对应的 BuildXXXCmd 函数
|
||||
*/
|
||||
196
module/cmd/cmd_types.h
Normal file
196
module/cmd/cmd_types.h
Normal file
@ -0,0 +1,196 @@
|
||||
/*
|
||||
* CMD 模块 V2 - 类型定义
|
||||
* 统一的输入/输出抽象层
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ========================================================================== */
|
||||
/* 错误码定义 */
|
||||
/* ========================================================================== */
|
||||
#define CMD_OK (0)
|
||||
#define CMD_ERR_NULL (-1)
|
||||
#define CMD_ERR_MODE (-2)
|
||||
#define CMD_ERR_SOURCE (-3)
|
||||
#define CMD_ERR_NO_INPUT (-4)
|
||||
|
||||
/* ========================================================================== */
|
||||
/* 输入源配置宏表 */
|
||||
/* ========================================================================== */
|
||||
/*
|
||||
* 使用方法:在config中定义需要启用的输入源
|
||||
* 格式: X(枚举名, 优先级, 适配器初始化函数, 获取数据函数)
|
||||
*/
|
||||
#define CMD_INPUT_SOURCE_TABLE(X) \
|
||||
X(RC, CMD_RC_AdapterInit, CMD_RC_GetInput) \
|
||||
X(PC, CMD_PC_AdapterInit, CMD_PC_GetInput) \
|
||||
X(NUC, CMD_NUC_AdapterInit, CMD_NUC_GetInput) \
|
||||
X(REF, CMD_REF_AdapterInit, CMD_REF_GetInput)
|
||||
|
||||
/* 输出模块配置宏表 */
|
||||
#define CMD_OUTPUT_MODULE_TABLE(X) \
|
||||
X(CHASSIS, Chassis_CMD_t, chassis) \
|
||||
X(GIMBAL, Gimbal_CMD_t, gimbal) \
|
||||
X(SHOOT, Shoot_CMD_t, shoot)
|
||||
|
||||
|
||||
/* ========================================================================== */
|
||||
/* 输入源枚举 */
|
||||
/* ========================================================================== */
|
||||
#define ENUM_INPUT_SOURCE(name, ...) CMD_SRC_##name,
|
||||
typedef enum {
|
||||
CMD_INPUT_SOURCE_TABLE(ENUM_INPUT_SOURCE)
|
||||
CMD_SRC_NUM
|
||||
} CMD_InputSource_t;
|
||||
#undef ENUM_INPUT_SOURCE
|
||||
|
||||
/* ========================================================================== */
|
||||
/* 统一输入数据结构 */
|
||||
/* ========================================================================== */
|
||||
|
||||
/* 摇杆数据 - 统一为-1.0 ~ 1.0 */
|
||||
typedef struct {
|
||||
float x;
|
||||
float y;
|
||||
} CMD_Joystick_t;
|
||||
|
||||
/* 开关位置 */
|
||||
typedef enum {
|
||||
CMD_SW_ERR = 0,
|
||||
CMD_SW_UP,
|
||||
CMD_SW_MID,
|
||||
CMD_SW_DOWN,
|
||||
} CMD_SwitchPos_t;
|
||||
|
||||
/* 鼠标数据 */
|
||||
typedef struct {
|
||||
int16_t x; /* 鼠标X轴移动速度 */
|
||||
int16_t y; /* 鼠标Y轴移动速度 */
|
||||
int16_t z; /* 鼠标滚轮 */
|
||||
bool l_click; /* 左键 */
|
||||
bool r_click; /* 右键 */
|
||||
bool m_click; /* 中键 */
|
||||
} CMD_Mouse_t;
|
||||
|
||||
/* 键盘数据 - 最多支持32个按键 */
|
||||
typedef struct {
|
||||
uint32_t bitmap; /* 按键位图 */
|
||||
} CMD_Keyboard_t;
|
||||
|
||||
/* 键盘按键索引 */
|
||||
typedef enum {
|
||||
CMD_KEY_W = (1 << 0), CMD_KEY_S = (1 << 1), CMD_KEY_A = (1 << 2), CMD_KEY_D = (1 << 3),
|
||||
CMD_KEY_SHIFT = (1 << 4), CMD_KEY_CTRL = (1 << 5), CMD_KEY_Q = (1 << 6), CMD_KEY_E = (1 << 7),
|
||||
CMD_KEY_R = (1 << 8), CMD_KEY_F = (1 << 9), CMD_KEY_G = (1 << 10), CMD_KEY_Z = (1 << 11),
|
||||
CMD_KEY_X = (1 << 12), CMD_KEY_C = (1 << 13), CMD_KEY_V = (1 << 14), CMD_KEY_B = (1 << 15),
|
||||
CMD_KEY_NUM
|
||||
} CMD_KeyIndex_t;
|
||||
|
||||
/* 裁判系统数据 */
|
||||
typedef struct {
|
||||
uint8_t game_status; /* 比赛状态 */
|
||||
} CMD_Referee_t;
|
||||
|
||||
typedef struct {
|
||||
CMD_Joystick_t joy_left; /* 左摇杆 */
|
||||
CMD_Joystick_t joy_right; /* 右摇杆 */
|
||||
CMD_SwitchPos_t sw[4]; /* 4个拨杆 */
|
||||
float dial; /* 拨轮 */
|
||||
} CMD_RawInput_RC_t;
|
||||
|
||||
typedef struct {
|
||||
CMD_Mouse_t mouse;
|
||||
CMD_Keyboard_t keyboard;
|
||||
} CMD_RawInput_PC_t;
|
||||
|
||||
typedef struct {
|
||||
int a;
|
||||
} CMD_RawInput_NUC_t;
|
||||
|
||||
typedef struct {
|
||||
CMD_Referee_t referee;
|
||||
} CMD_RawInput_REF_t;
|
||||
|
||||
/* 统一的原始输入结构 - 所有设备适配后都转换成这个格式 */
|
||||
typedef struct {
|
||||
bool online[CMD_SRC_NUM];
|
||||
|
||||
/* 遥控器部分 */
|
||||
CMD_RawInput_RC_t rc;
|
||||
|
||||
/* PC部分 */
|
||||
CMD_RawInput_PC_t pc;
|
||||
|
||||
/* NUC部分 */
|
||||
/* 暂无定义,预留扩展 */
|
||||
CMD_RawInput_NUC_t nuc;
|
||||
|
||||
/* REF部分 - 裁判系统数据 */
|
||||
CMD_RawInput_REF_t ref;
|
||||
} CMD_RawInput_t;
|
||||
|
||||
/* ========================================================================== */
|
||||
/* 模块掩码 */
|
||||
/* ========================================================================== */
|
||||
typedef enum {
|
||||
CMD_MODULE_NONE = (1 << 0),
|
||||
CMD_MODULE_CHASSIS = (1 << 1),
|
||||
CMD_MODULE_GIMBAL = (1 << 2),
|
||||
CMD_MODULE_SHOOT = (1 << 3),
|
||||
CMD_MODULE_ALL = 0x0E
|
||||
} CMD_ModuleMask_t;
|
||||
|
||||
/* ========================================================================== */
|
||||
/* 行为定义 */
|
||||
/* ========================================================================== */
|
||||
/* 行为-按键映射宏表 */
|
||||
#define BEHAVIOR_CONFIG_COUNT (11)
|
||||
#define CMD_BEHAVIOR_TABLE(X) \
|
||||
X(FORE, CMD_KEY_W, CMD_ACTIVE_PRESSED, CMD_MODULE_CHASSIS) \
|
||||
X(BACK, CMD_KEY_S, CMD_ACTIVE_PRESSED, CMD_MODULE_CHASSIS) \
|
||||
X(LEFT, CMD_KEY_A, CMD_ACTIVE_PRESSED, CMD_MODULE_CHASSIS) \
|
||||
X(RIGHT, CMD_KEY_D, CMD_ACTIVE_PRESSED, CMD_MODULE_CHASSIS) \
|
||||
X(ACCELERATE, CMD_KEY_SHIFT, CMD_ACTIVE_PRESSED, CMD_MODULE_CHASSIS) \
|
||||
X(DECELERATE, CMD_KEY_CTRL, CMD_ACTIVE_PRESSED, CMD_MODULE_CHASSIS) \
|
||||
X(FIRE, CMD_KEY_L_CLICK, CMD_ACTIVE_PRESSED, CMD_MODULE_SHOOT) \
|
||||
X(FIRE_MODE, CMD_KEY_B, CMD_ACTIVE_RISING_EDGE, CMD_MODULE_SHOOT) \
|
||||
X(ROTOR, CMD_KEY_E, CMD_ACTIVE_PRESSED, CMD_MODULE_CHASSIS) \
|
||||
X(AUTOAIM, CMD_KEY_R, CMD_ACTIVE_RISING_EDGE, CMD_MODULE_GIMBAL | CMD_MODULE_SHOOT) \
|
||||
X(CHECKSOURCERCPC, CMD_KEY_CTRL|CMD_KEY_SHIFT|CMD_KEY_V, CMD_ACTIVE_RISING_EDGE, CMD_MODULE_NONE)
|
||||
/* 触发类型 */
|
||||
typedef enum {
|
||||
CMD_ACTIVE_PRESSED, /* 按住时触发 */
|
||||
CMD_ACTIVE_RISING_EDGE, /* 按下瞬间触发 */
|
||||
CMD_ACTIVE_FALLING_EDGE, /* 松开瞬间触发 */
|
||||
} CMD_TriggerType_t;
|
||||
|
||||
/* 特殊按键值 */
|
||||
#define CMD_KEY_NONE 0xFF
|
||||
#define CMD_KEY_L_CLICK (1 << 31)
|
||||
#define CMD_KEY_R_CLICK (1 << 30)
|
||||
#define CMD_KEY_M_CLICK (1 << 29)
|
||||
|
||||
/* 行为枚举 - 由宏表自动生成 */
|
||||
#define ENUM_BEHAVIOR(name, key, trigger, mask) CMD_BEHAVIOR_##name,
|
||||
typedef enum {
|
||||
CMD_BEHAVIOR_TABLE(ENUM_BEHAVIOR)
|
||||
CMD_BEHAVIOR_NUM
|
||||
} CMD_Behavior_t;
|
||||
#undef ENUM_BEHAVIOR
|
||||
|
||||
/* ========================================================================== */
|
||||
/* 键盘辅助宏 */
|
||||
/* ========================================================================== */
|
||||
#define CMD_KEY_PRESSED(kb, key) (((kb)->bitmap >> (key)) & 1)
|
||||
#define CMD_KEY_SET(kb, key) ((kb)->bitmap |= (1 << (key)))
|
||||
#define CMD_KEY_CLEAR(kb, key) ((kb)->bitmap &= ~(1 << (key)))
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
Loading…
Reference in New Issue
Block a user