mirror of
https://gitee.com/dlmu-cone/bf_original_balance_chassis
synced 2026-07-23 19:25:09 +08:00
云台跟随,连续发射
This commit is contained in:
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
@@ -43,7 +43,7 @@
|
||||
"interface": "swd",
|
||||
"svdFile": "STM32F407.svd",
|
||||
"rtos": "FreeRTOS",
|
||||
"preLaunchTask": "build task",//先运行Build任务,取消注释即可使用
|
||||
//"preLaunchTask": "build task",//先运行Build任务,取消注释即可使用
|
||||
"liveWatch": {
|
||||
"enabled": true,
|
||||
"samplesPerSecond": 4
|
||||
|
||||
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
@@ -5,7 +5,10 @@
|
||||
"stdlib.h": "c",
|
||||
"bsp_can.h": "c",
|
||||
"math.h": "c",
|
||||
"user_lib.h": "c"
|
||||
"user_lib.h": "c",
|
||||
"servo_motor.h": "c",
|
||||
"main.h": "c",
|
||||
"buzzer.h": "c"
|
||||
},
|
||||
"C_Cpp.errorSquiggles": "disabled"
|
||||
}
|
||||
@@ -19,18 +19,18 @@
|
||||
#include "lqr_calc.h"
|
||||
#include "speed_estimation.h"
|
||||
#include "fly_detection.h"
|
||||
|
||||
#include "buzzer.h"
|
||||
// 计时变量
|
||||
static uint32_t balance_dwt_cnt;
|
||||
static float del_t;
|
||||
|
||||
// 底盘拥有的实例模块
|
||||
static INS_t *Chassis_IMU_data;
|
||||
static RC_ctrl_t *rc_data; // 底盘单独调试用
|
||||
static RC_ctrl_t *rc_data; // 底盘单独调试用
|
||||
static Chassis_Ctrl_Cmd_s chassis_cmd_recv;
|
||||
|
||||
static Chassis_Upload_Data_s chassis_feedback_data; // 底盘反馈数据
|
||||
// 四个关节电机和两个驱动轮电机
|
||||
static HTMotorInstance *lf, *lb, *rf, *rb, *joint[4]; // 指针数组方便传参和调试
|
||||
static HTMotorInstance *lf, *lb, *rf, *rb, *joint[4]; // 指针数组方便传参和调试
|
||||
static LKMotorInstance *l_driven, *r_driven, *driven[2];
|
||||
|
||||
// 两个腿的参数,0为左腿,1为右腿
|
||||
@@ -38,23 +38,35 @@ static LinkNPodParam l_side, r_side;
|
||||
static ChassisParam chassis;
|
||||
|
||||
// 综合运动补偿的PID控制器
|
||||
static PIDInstance leglen_pid_l, leglen_pid_r; // 用PD模拟弹簧, 不要积分(弹簧是无积分二阶系统), 增益不可过大否则抗外界冲击响应时太"硬"
|
||||
static PIDInstance roll_compensate_pid; // roll轴补偿,用于保持机体水平
|
||||
static PIDInstance steer_p_pid, steer_v_pid; // 转向PID,有转向指令时使用IMU的加速度反馈积分以获取速度和位置状态量
|
||||
static PIDInstance anti_crash_pid; // 抗劈叉,将输出以相反的方向叠加到左右腿的上
|
||||
static PIDInstance leglen_pid_l, leglen_pid_r; // 用PD模拟弹簧, 不要积分(弹簧是无积分二阶系统), 增益不可过大否则抗外界冲击响应时太"硬"
|
||||
static PIDInstance roll_compensate_pid; // roll轴补偿,用于保持机体水平
|
||||
static PIDInstance steer_p_pid, steer_v_pid; // 转向PID,有转向指令时使用IMU的加速度反馈积分以获取速度和位置状态量
|
||||
static PIDInstance anti_crash_pid; // 抗劈叉,将输出以相反的方向叠加到左右腿的上
|
||||
|
||||
// 底盘状态
|
||||
static Robot_Status_e chassis_status;
|
||||
|
||||
static referee_info_t* referee_data; // 用于获取裁判系统的数据
|
||||
static referee_info_t *referee_data; // 用于获取裁判系统的数据
|
||||
static Referee_Interactive_info_t ui_data; // UI数据,将底盘中的数据传入此结构体的对应变量中,UI会自动检测是否变化,对应显示UI
|
||||
|
||||
static CANCommInstance *cmd_can_comm; // 底盘CAN通信实例
|
||||
|
||||
void BalanceInit()
|
||||
{
|
||||
rc_data = RemoteControlInit(&huart3);
|
||||
Chassis_IMU_data = INS_Init();
|
||||
referee_data = UITaskInit(&huart6, &ui_data); // 裁判系统初始化,会同时初始化UI
|
||||
|
||||
CANComm_Init_Config_s comm_conf = {
|
||||
.can_config = {
|
||||
.can_handle = &hcan2,
|
||||
.tx_id = 0x311,
|
||||
.rx_id = 0x312,
|
||||
},
|
||||
.recv_data_len = sizeof(Chassis_Ctrl_Cmd_s),
|
||||
.send_data_len = sizeof(Chassis_Upload_Data_s),
|
||||
};
|
||||
cmd_can_comm = CANCommInit(&comm_conf);
|
||||
// 关节电机
|
||||
Motor_Init_Config_s joint_conf = {
|
||||
// 写一个,剩下的修改方向和id即可
|
||||
@@ -173,7 +185,7 @@ void BalanceInit()
|
||||
|
||||
// 状态初始化
|
||||
l_side.target_len = r_side.target_len = 0.12;
|
||||
chassis.vel_cov = 100; // 速度协方差初始化
|
||||
chassis.vel_cov = 100; // 速度协方差初始化
|
||||
chassis_status = ROBOT_READY;
|
||||
DWT_GetDeltaT(&balance_dwt_cnt);
|
||||
}
|
||||
@@ -191,7 +203,7 @@ static uint8_t JointMotorIsLost()
|
||||
{
|
||||
for (uint8_t i = 0; i < JOINT_CNT; i++)
|
||||
{
|
||||
if(joint[i]->motor_daemon->temp_count == 0)
|
||||
if (joint[i]->motor_daemon->temp_count == 0)
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -201,9 +213,9 @@ static uint8_t JointMotorIsLost()
|
||||
// 检查驱动轮电机是否离线
|
||||
static uint8_t DrivenMotorIsLost()
|
||||
{
|
||||
for(uint8_t i = 0; i < DRIVEN_CNT; i++)
|
||||
for (uint8_t i = 0; i < DRIVEN_CNT; i++)
|
||||
{
|
||||
if(driven[i]->daemon->temp_count == 0)
|
||||
if (driven[i]->daemon->temp_count == 0)
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -232,21 +244,22 @@ static void ControlSwitch()
|
||||
}
|
||||
else
|
||||
{
|
||||
chassis_cmd_recv.chassis_mode = CHASSIS_FREE_DEBUG; // 自由转动&前后
|
||||
chassis_cmd_recv.vx = 0.003 * (float)rc_data[TEMP].rc.rocker_r1; // speed x, unit m/s
|
||||
chassis_cmd_recv.chassis_mode = CHASSIS_FREE_DEBUG; // 自由转动&前后
|
||||
chassis_cmd_recv.vx = 0.003 * (float)rc_data[TEMP].rc.rocker_r1; // speed x, unit m/s
|
||||
chassis_cmd_recv.delta_leglen = -0.0000005f * (float)rc_data[TEMP].rc.dial;
|
||||
chassis_cmd_recv.offset_angle -= 0.000005 * (float)rc_data[TEMP].rc.rocker_r_;
|
||||
}
|
||||
}
|
||||
else
|
||||
chassis_cmd_recv.chassis_mode = CHASSIS_ZERO_FORCE; // 皆离线,急停
|
||||
{
|
||||
chassis_cmd_recv = *(Chassis_Ctrl_Cmd_s *)CANCommGet(cmd_can_comm);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* 腿缩回复位,只允许驱动轮电机移动 */
|
||||
static void ResetChassis()
|
||||
{
|
||||
EnableAllMotor(); // 打开全部电机,关节复位到起始角度,驱动电机响应速度输入以从墙角或固连中脱身
|
||||
EnableAllMotor(); // 打开全部电机,关节复位到起始角度,驱动电机响应速度输入以从墙角或固连中脱身
|
||||
|
||||
// 目标速度置0
|
||||
chassis.target_v = 0;
|
||||
@@ -278,7 +291,7 @@ static void ResetChassis()
|
||||
for (uint8_t i = 0; i < JOINT_CNT; i++)
|
||||
HTMotorOuterLoop(joint[i], OPEN_LOOP); // 改回直接开环扭矩输入,让电调对扭矩闭环
|
||||
|
||||
return; // 退出函数不再执行关节指令
|
||||
return; // 退出函数不再执行关节指令
|
||||
}
|
||||
else
|
||||
chassis_status = ROBOT_STOP;
|
||||
@@ -291,7 +304,6 @@ static void ResetChassis()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 工作状态设定
|
||||
static void WokingStateSet()
|
||||
{
|
||||
@@ -334,8 +346,11 @@ static void WokingStateSet()
|
||||
chassis.target_v += sign(chassis_cmd_recv.vx - chassis.target_v) * MAX_ACC_REF * del_t;
|
||||
|
||||
// 角度输入
|
||||
chassis.target_yaw = chassis_cmd_recv.offset_angle;
|
||||
|
||||
if (chassis_cmd_recv.chassis_mode == CHASSIS_FREE_DEBUG)
|
||||
{
|
||||
chassis.target_yaw = chassis_cmd_recv.offset_angle;
|
||||
}
|
||||
chassis.target_yaw = chassis.yaw + chassis_cmd_recv.offset_angle*DEGREE_2_RAD;
|
||||
// TODO 转向速度限幅
|
||||
|
||||
// TODO 最大dist误差限幅
|
||||
@@ -343,7 +358,6 @@ static void WokingStateSet()
|
||||
// TODO 最大速度误差限幅
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 将电机和imu的数据组装为LinkNPodParam结构体和chassisParam结构体
|
||||
*
|
||||
@@ -375,16 +389,11 @@ static void ParamAssemble()
|
||||
r_side.w_ecd = -r_driven->measure.speed_rads;
|
||||
}
|
||||
|
||||
|
||||
static void SynthesizeMotion() /* 腿部控制:抗劈叉; 轮子控制:转向 */
|
||||
{
|
||||
if (chassis_cmd_recv.chassis_mode == CHASSIS_FREE_DEBUG)
|
||||
{
|
||||
// 双环控制
|
||||
float p_ref = PIDCalculate(&steer_p_pid, chassis.yaw, chassis.target_yaw);
|
||||
PIDCalculate(&steer_v_pid, chassis.wz, p_ref);
|
||||
}
|
||||
|
||||
float p_ref = PIDCalculate(&steer_p_pid, chassis.yaw, chassis.target_yaw);
|
||||
PIDCalculate(&steer_v_pid, chassis.wz, p_ref);
|
||||
l_side.T_wheel -= steer_v_pid.Output;
|
||||
r_side.T_wheel += steer_v_pid.Output;
|
||||
|
||||
@@ -396,7 +405,6 @@ static void SynthesizeMotion() /* 腿部控制:抗劈叉; 轮子控制:转向 */
|
||||
r_side.T_hip -= anti_crash_pid.Output - swerving_speed_ff;
|
||||
}
|
||||
|
||||
|
||||
static void LegControl() /* 腿长控制和Roll补偿 */
|
||||
{
|
||||
PIDCalculate(&roll_compensate_pid, chassis.roll, 0);
|
||||
@@ -423,7 +431,7 @@ static void WattLimitSet() /* 设定运动模态的输出 */
|
||||
void BalanceTask()
|
||||
{
|
||||
del_t = DWT_GetDeltaT(&balance_dwt_cnt);
|
||||
|
||||
BuzzerOn();
|
||||
// 切换遥控器控制or云台板控制
|
||||
ControlSwitch();
|
||||
// 设置目标参数和工作模式
|
||||
@@ -457,4 +465,5 @@ void BalanceTask()
|
||||
|
||||
// 运动模态,电机输出映射和限幅
|
||||
WattLimitSet();
|
||||
CANCommSend(cmd_can_comm, (void *)&chassis_feedback_data);
|
||||
}
|
||||
@@ -9,18 +9,238 @@
|
||||
#include "general_def.h"
|
||||
#include "dji_motor.h"
|
||||
#include "bmi088.h"
|
||||
#include "user_lib.h"
|
||||
#include "can_comm.h"
|
||||
// bsp
|
||||
#include "bsp_dwt.h"
|
||||
#include "bsp_log.h"
|
||||
// 私有宏,自动将编码器转换成角度值
|
||||
#define PTICH_HORIZON_ANGLE (PITCH_HORIZON_ECD * ECD_ANGLE_COEF_DJI) // pitch水平时电机的角度,0-360
|
||||
|
||||
float yaw_align_angle = 0.0f, yaw_chassis_align_ecd = 2716;
|
||||
static Publisher_t *chassis_cmd_pub; // 底盘控制消息发布者
|
||||
static Subscriber_t *chassis_feed_sub; // 底盘反馈信息订阅者
|
||||
static Chassis_Ctrl_Cmd_s chassis_cmd_send; // 发送给底盘应用的信息,包括控制信息和UI绘制相关
|
||||
static Chassis_Upload_Data_s chassis_fetch_data; // 从底盘应用接收的反馈信息信息,底盘功率枪口热量与底盘运动状态等
|
||||
|
||||
static RC_ctrl_t *rc_data; // 遥控器数据,初始化时返回
|
||||
static Vision_Recv_s *vision_recv_data; // 视觉接收数据指针,初始化时返回
|
||||
static Vision_Send_s vision_send_data; // 视觉发送数据
|
||||
|
||||
static Publisher_t *gimbal_cmd_pub; // 云台控制消息发布者
|
||||
static Subscriber_t *gimbal_feed_sub; // 云台反馈信息订阅者
|
||||
static Gimbal_Ctrl_Cmd_s gimbal_cmd_send; // 传递给云台的控制信息
|
||||
static Gimbal_Upload_Data_s gimbal_fetch_data; // 从云台获取的反馈信息
|
||||
|
||||
static Publisher_t *shoot_cmd_pub; // 发射控制消息发布者
|
||||
static Subscriber_t *shoot_feed_sub; // 发射反馈信息订阅者
|
||||
static Shoot_Ctrl_Cmd_s shoot_cmd_send; // 传递给发射的控制信息
|
||||
static Shoot_Upload_Data_s shoot_fetch_data; // 从发射获取的反馈信息
|
||||
|
||||
static Robot_Status_e robot_state; // 机器人整体工作状态
|
||||
|
||||
static Work_Mode_e vision_work_mode; // 视觉工作模式
|
||||
|
||||
static CANCommInstance *cmd_can_comm; // 底盘CAN通信实例
|
||||
void RobotCMDInit()
|
||||
{
|
||||
rc_data = RemoteControlInit(&huart3); // 修改为对应串口,注意如果是自研板dbus协议串口需选用添加了反相器的那个
|
||||
vision_recv_data = VisionInit(&huart1); // 视觉通信串口
|
||||
|
||||
gimbal_cmd_pub = PubRegister("gimbal_cmd", sizeof(Gimbal_Ctrl_Cmd_s));
|
||||
gimbal_feed_sub = SubRegister("gimbal_feed", sizeof(Gimbal_Upload_Data_s));
|
||||
shoot_cmd_pub = PubRegister("shoot_cmd", sizeof(Shoot_Ctrl_Cmd_s));
|
||||
shoot_feed_sub = SubRegister("shoot_feed", sizeof(Shoot_Upload_Data_s));
|
||||
|
||||
CANComm_Init_Config_s comm_conf = {
|
||||
.can_config = {
|
||||
.can_handle = &hcan1,
|
||||
.tx_id = 0x312,
|
||||
.rx_id = 0x311,
|
||||
},
|
||||
.recv_data_len = sizeof(Chassis_Upload_Data_s),
|
||||
.send_data_len = sizeof(Chassis_Ctrl_Cmd_s),
|
||||
};
|
||||
cmd_can_comm = CANCommInit(&comm_conf);
|
||||
|
||||
gimbal_cmd_send.pitch = 0;
|
||||
gimbal_cmd_send.yaw = 0;
|
||||
gimbal_cmd_send.gimbal_mode = GIMBAL_ZERO_FORCE;
|
||||
chassis_cmd_send.chassis_mode = CHASSIS_ZERO_FORCE;
|
||||
|
||||
robot_state = ROBOT_STOP; // 启动时机器人进入工作模式,后续加入所有应用初始化完成之后再进入
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 根据gimbal app传回的当前电机角度计算和零位的误差
|
||||
* 单圈绝对角度的范围是0~360,说明文档中有图示
|
||||
*
|
||||
*/
|
||||
static void CalcOffsetAngle()
|
||||
{
|
||||
// 别名angle提高可读性,不然太长了不好看,虽然基本不会动这个函数
|
||||
static float angle;
|
||||
yaw_align_angle = yaw_chassis_align_ecd * ECD_ANGLE_COEF_DJI; // 从底盘获取的yaw电机对齐角度
|
||||
angle = gimbal_fetch_data.yaw_motor_single_round_angle; // 从云台获取的当前yaw电机单圈角度
|
||||
if (yaw_chassis_align_ecd > 4096) // 如果大于180度
|
||||
{
|
||||
if (angle > yaw_align_angle)
|
||||
chassis_cmd_send.offset_angle = angle - yaw_align_angle;
|
||||
else if (angle <= yaw_align_angle && angle >= yaw_align_angle - 180.0f)
|
||||
chassis_cmd_send.offset_angle = angle - yaw_align_angle;
|
||||
else
|
||||
chassis_cmd_send.offset_angle = angle - yaw_align_angle + 360.0f;
|
||||
}
|
||||
else
|
||||
{ // 小于180度
|
||||
if (angle > yaw_align_angle && angle <= 180.0f + yaw_align_angle)
|
||||
chassis_cmd_send.offset_angle = angle - yaw_align_angle;
|
||||
else if (angle > 180.0f + yaw_align_angle)
|
||||
chassis_cmd_send.offset_angle = angle - yaw_align_angle - 360.0f;
|
||||
else
|
||||
chassis_cmd_send.offset_angle = angle - yaw_align_angle;
|
||||
}
|
||||
}
|
||||
|
||||
void RobotCMDTask()
|
||||
/**
|
||||
* @brief 控制输入为遥控器(调试时)的模式和控制量设置
|
||||
*
|
||||
*/
|
||||
static void RemoteControlSet()
|
||||
{
|
||||
shoot_cmd_send.bullet_speed = 30;
|
||||
// // 云台参数,确定云台控制数据
|
||||
// if (switch_is_mid(rc_data[TEMP].rc.switch_left)) // 左侧开关状态为[中],视觉模式
|
||||
// {
|
||||
// gimbal_cmd_send.yaw = ( vision_recv_data->yaw == 0 ? gimbal_cmd_send.yaw : vision_recv_data->yaw );
|
||||
// gimbal_cmd_send.pitch =( vision_recv_data->pitch == 0 ? gimbal_cmd_send.pitch : vision_recv_data->pitch );
|
||||
// }
|
||||
// 左侧开关状态为[下],或视觉未识别到目标,纯遥控器拨杆控制
|
||||
chassis_cmd_send.vx = 0.0f;
|
||||
if (abs(rc_data[TEMP].rc.rocker_r1) > 300)
|
||||
{
|
||||
chassis_cmd_send.vx = 0.003f * (float)rc_data[TEMP].rc.rocker_r1; // _水平方向
|
||||
yaw_chassis_align_ecd = 2716;
|
||||
}
|
||||
else if (abs(rc_data[TEMP].rc.rocker_r_) > 300)
|
||||
{
|
||||
chassis_cmd_send.vx = 0.003f * (float)rc_data[TEMP].rc.rocker_r_; // _水平方向
|
||||
yaw_chassis_align_ecd = 765;
|
||||
}
|
||||
|
||||
gimbal_cmd_send.yaw -= 0.001f * (float)rc_data[TEMP].rc.rocker_l_;
|
||||
gimbal_cmd_send.pitch -= 0.0004f * (float)rc_data[TEMP].rc.rocker_l1;
|
||||
// 摇杆控制的软件限位
|
||||
gimbal_cmd_send.pitch = float_constrain(gimbal_cmd_send.pitch, -35.0f, 30.0f);
|
||||
// gimbal_cmd_send.yaw = float_constrain(gimbal_cmd_send.yaw, -180.0f, 180.0f);
|
||||
|
||||
// 底盘参数,目前没有加入小陀螺(调试似乎暂时没有必要),系数需要调整
|
||||
|
||||
// 摩擦轮控制,拨轮向上打为负,向下为正
|
||||
if (rc_data[TEMP].rc.dial < -100) // 向上超过100,打开摩擦轮
|
||||
shoot_cmd_send.friction_mode = FRICTION_ON;
|
||||
else
|
||||
shoot_cmd_send.friction_mode = FRICTION_OFF;
|
||||
// 拨弹控制,遥控器固定为一种拨弹模式,可自行选择
|
||||
if (rc_data[TEMP].rc.dial < -400)
|
||||
shoot_cmd_send.load_mode = LOAD_BURSTFIRE;
|
||||
else
|
||||
shoot_cmd_send.load_mode = LOAD_STOP;
|
||||
// // 射频控制,固定每秒1发,后续可以根据左侧拨轮的值大小切换射频,
|
||||
// if( rc_data[TEMP].rc.switch_left == 3)
|
||||
// {
|
||||
// shoot_cmd_send.friction_mode = FRICTION_ON;
|
||||
// if(vision_recv_data->fire_mode ==AUTO_AIM)
|
||||
// shoot_cmd_send.load_mode = LOAD_1_BULLET;
|
||||
// else
|
||||
// shoot_cmd_send.load_mode = LOAD_STOP;
|
||||
// }
|
||||
shoot_cmd_send.shoot_rate = 15;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 输入为键鼠时模式和控制量设置
|
||||
*
|
||||
*/
|
||||
static void MouseKeySet()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 紧急停止,包括遥控器左上侧拨轮打满/重要模块离线/双板通信失效等
|
||||
* 停止的阈值'300'待修改成合适的值,或改为开关控制.
|
||||
*
|
||||
* @todo 后续修改为遥控器离线则电机停止(关闭遥控器急停),通过给遥控器模块添加daemon实现
|
||||
*
|
||||
*/
|
||||
static void EmergencyHandler()
|
||||
{
|
||||
|
||||
if (switch_is_down(rc_data[TEMP].rc.switch_left) || switch_is_mid(rc_data[TEMP].rc.switch_left)) // 遥控器左侧开关状态为[下],遥控器控制
|
||||
{
|
||||
if (rc_data[TEMP].rc.dial > 300 || robot_state == ROBOT_STOP) // 还需添加重要应用和模块离线的判断
|
||||
{
|
||||
robot_state = ROBOT_STOP;
|
||||
gimbal_cmd_send.gimbal_mode = GIMBAL_ZERO_FORCE;
|
||||
chassis_cmd_send.chassis_mode = CHASSIS_ZERO_FORCE;
|
||||
shoot_cmd_send.shoot_mode = SHOOT_OFF;
|
||||
shoot_cmd_send.friction_mode = FRICTION_OFF;
|
||||
|
||||
gimbal_cmd_send.yaw = gimbal_fetch_data.gimbal_imu_data.YawTotalAngle; // 急停时设定值保持与实际值同步,避免恢复时疯转
|
||||
gimbal_cmd_send.pitch = gimbal_fetch_data.gimbal_imu_data.Pitch;
|
||||
}
|
||||
// 遥控器右侧开关为[上],恢复正常运行
|
||||
if (switch_is_up(rc_data[TEMP].rc.switch_right))
|
||||
{
|
||||
robot_state = ROBOT_READY;
|
||||
shoot_cmd_send.shoot_mode = SHOOT_ON;
|
||||
gimbal_cmd_send.gimbal_mode = GIMBAL_GYRO_MODE;
|
||||
chassis_cmd_send.chassis_mode = CHASSIS_FOLLOW_GIMBAL_YAW;
|
||||
}
|
||||
}
|
||||
else if (switch_is_up(rc_data[TEMP].rc.switch_left)) // 遥控器左侧开关状态为[上],键盘控制
|
||||
{
|
||||
switch (rc_data[TEMP].key_count[KEY_PRESS_WITH_CTRL][Key_C] % 2) // ctrl+c 进入急停
|
||||
{
|
||||
case 0:
|
||||
robot_state = ROBOT_READY;
|
||||
shoot_cmd_send.shoot_mode = SHOOT_ON;
|
||||
break;
|
||||
|
||||
default:
|
||||
robot_state = ROBOT_STOP;
|
||||
gimbal_cmd_send.gimbal_mode = GIMBAL_ZERO_FORCE;
|
||||
chassis_cmd_send.chassis_mode = CHASSIS_ZERO_FORCE;
|
||||
shoot_cmd_send.shoot_mode = SHOOT_OFF;
|
||||
shoot_cmd_send.friction_mode = FRICTION_OFF;
|
||||
shoot_cmd_send.load_mode = LOAD_STOP;
|
||||
|
||||
gimbal_cmd_send.yaw = gimbal_fetch_data.gimbal_imu_data.YawTotalAngle; // 急停时设定值保持与实际值同步,避免恢复时疯转
|
||||
gimbal_cmd_send.pitch = gimbal_fetch_data.gimbal_imu_data.Pitch;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* 机器人核心控制任务,200Hz频率运行(必须高于视觉发送频率) */
|
||||
void RobotCMDTask()
|
||||
{
|
||||
chassis_fetch_data = *(Chassis_Upload_Data_s *)CANCommGet(cmd_can_comm);
|
||||
|
||||
SubGetMessage(shoot_feed_sub, &shoot_fetch_data);
|
||||
SubGetMessage(gimbal_feed_sub, &gimbal_fetch_data);
|
||||
|
||||
// 根据gimbal的反馈值计算云台和底盘正方向的夹角,不需要传参,通过static私有变量完成
|
||||
CalcOffsetAngle();
|
||||
// 根据遥控器左侧开关,确定当前使用的控制模式为遥控器调试还是键鼠
|
||||
if (switch_is_down(rc_data[TEMP].rc.switch_left) || switch_is_mid(rc_data[TEMP].rc.switch_left)) // 遥控器左侧开关状态为[下],遥控器控制
|
||||
RemoteControlSet();
|
||||
if (switch_is_up(rc_data[TEMP].rc.switch_left)) // 遥控器左侧开关状态为[上],键盘控制
|
||||
MouseKeySet();
|
||||
|
||||
EmergencyHandler(); // 处理模块离线和遥控器急停等紧急情况
|
||||
|
||||
CANCommSend(cmd_can_comm, (void *)&chassis_cmd_send);
|
||||
|
||||
PubPushMessage(shoot_cmd_pub, (void *)&shoot_cmd_send);
|
||||
PubPushMessage(gimbal_cmd_pub, (void *)&gimbal_cmd_send);
|
||||
}
|
||||
|
||||
@@ -4,16 +4,169 @@
|
||||
#include "ins_task.h"
|
||||
#include "message_center.h"
|
||||
#include "general_def.h"
|
||||
#include "buzzer.h"
|
||||
#include "bmi088.h"
|
||||
|
||||
static INS_t *gimba_IMU_data; // 云台IMU数据
|
||||
static DJIMotorInstance *yaw_motor, *pitch_motor;
|
||||
|
||||
static Publisher_t *gimbal_pub; // 云台应用消息发布者(云台反馈给cmd)
|
||||
static Subscriber_t *gimbal_sub; // cmd控制消息订阅者
|
||||
static Gimbal_Upload_Data_s gimbal_feedback_data; // 回传给cmd的云台状态信息
|
||||
static Gimbal_Ctrl_Cmd_s gimbal_cmd_recv; // 来自cmd的控制信息
|
||||
|
||||
void GimbalInit()
|
||||
{
|
||||
gimba_IMU_data = INS_Init(); // IMU先初始化,获取姿态数据指针赋给yaw电机的其他数据来源
|
||||
// YAW
|
||||
Motor_Init_Config_s yaw_config = {
|
||||
.can_init_config = {
|
||||
.can_handle = &hcan1,
|
||||
.tx_id = 4,
|
||||
},
|
||||
.controller_param_init_config = {
|
||||
.angle_PID = {
|
||||
.Kp = 0.5, //0.55
|
||||
.Ki = 0.0,//0.05
|
||||
.Kd = 0.0,//0.02
|
||||
.CoefA =0.0,//0.5
|
||||
.CoefB = 0.0,//0.6
|
||||
.Output_LPF_RC = 0,
|
||||
.DeadBand = 0.0,//0.02
|
||||
.Derivative_LPF_RC=0.0,//0.008
|
||||
.Improve = PID_Trapezoid_Intergral |PID_ChangingIntegrationRate| PID_Integral_Limit |PID_Derivative_On_Measurement | PID_OutputFilter |PID_DerivativeFilter,
|
||||
.IntegralLimit = 0.0,
|
||||
|
||||
.MaxOut = 400,
|
||||
},
|
||||
.speed_PID = {
|
||||
.Kp = 15000,//22000
|
||||
.Ki = 0,//
|
||||
.Kd =0,
|
||||
// .CoefA = 0.8,
|
||||
// .CoefB = 0.1,
|
||||
.Output_LPF_RC = 0.0,//0.002
|
||||
.Improve = PID_Trapezoid_Intergral |PID_Integral_Limit |PID_Derivative_On_Measurement | PID_OutputFilter,
|
||||
.IntegralLimit = 0,
|
||||
.MaxOut = 20000,
|
||||
},
|
||||
.other_angle_feedback_ptr = &gimba_IMU_data->YawTotalAngle,
|
||||
// 还需要增加角速度额外反馈指针,注意方向,ins_task.md中有c板的bodyframe坐标系说明
|
||||
.other_speed_feedback_ptr=&gimba_IMU_data->Gyro[2],
|
||||
},
|
||||
.controller_setting_init_config = {
|
||||
.angle_feedback_source = OTHER_FEED,
|
||||
.speed_feedback_source = OTHER_FEED,
|
||||
.outer_loop_type = ANGLE_LOOP,
|
||||
.close_loop_type = ANGLE_LOOP | SPEED_LOOP,
|
||||
.motor_reverse_flag = MOTOR_DIRECTION_NORMAL,
|
||||
.feedforward_flag = SPEED_FEEDFORWARD,
|
||||
|
||||
},
|
||||
.motor_type = GM6020};
|
||||
// PITCH
|
||||
Motor_Init_Config_s pitch_config = {
|
||||
.can_init_config = {
|
||||
.can_handle = &hcan2,
|
||||
.tx_id = 3,
|
||||
},
|
||||
.controller_param_init_config = {
|
||||
.angle_PID = {
|
||||
.Kp =0.4,//0.4
|
||||
.Ki = 0.0,//0.15
|
||||
.Kd = 0.0,//0.006
|
||||
.CoefA = 0.0,//0.5
|
||||
.CoefB = 0.0,//0.6
|
||||
.DeadBand = 0.0,//0.005
|
||||
.Output_LPF_RC = 0.0,//0.01
|
||||
.Improve = PID_Trapezoid_Intergral |PID_ChangingIntegrationRate| PID_Integral_Limit| PID_OutputFilter|PID_DerivativeFilter,
|
||||
.IntegralLimit =1,//1
|
||||
.MaxOut = 600,//600
|
||||
},
|
||||
.speed_PID = {
|
||||
.Kp=10000,//14000
|
||||
.Ki =0,//0
|
||||
.Kd =0.0,//0.0005
|
||||
.CoefA =0,//1500
|
||||
.CoefB =0,//2000
|
||||
.Output_LPF_RC = 0.0,//0.005
|
||||
.Improve = PID_Trapezoid_Intergral | PID_Integral_Limit | PID_OutputFilter,
|
||||
.IntegralLimit =3000,//3000
|
||||
.MaxOut = 20000,//20000
|
||||
},
|
||||
.other_angle_feedback_ptr = &gimba_IMU_data->Pitch,
|
||||
// 还需要增加角速度额外反馈指针,注意方向,ins_task.md中有c板的bodyframe坐标系说明
|
||||
.other_speed_feedback_ptr = (&gimba_IMU_data->Gyro[0]),
|
||||
},
|
||||
.controller_setting_init_config = {
|
||||
.angle_feedback_source = OTHER_FEED,
|
||||
.speed_feedback_source = OTHER_FEED,
|
||||
.outer_loop_type = ANGLE_LOOP,
|
||||
.close_loop_type = ANGLE_LOOP | SPEED_LOOP,
|
||||
.motor_reverse_flag = MOTOR_DIRECTION_NORMAL,
|
||||
.feedback_reverse_flag = FEEDBACK_DIRECTION_NORMAL,
|
||||
},
|
||||
.motor_type = GM6020,
|
||||
};
|
||||
// 电机对total_angle闭环,上电时为零,会保持静止,收到遥控器数据再动
|
||||
yaw_motor = DJIMotorInit(&yaw_config);
|
||||
pitch_motor = DJIMotorInit(&pitch_config);
|
||||
|
||||
gimbal_pub = PubRegister("gimbal_feed", sizeof(Gimbal_Upload_Data_s));
|
||||
gimbal_sub = SubRegister("gimbal_cmd", sizeof(Gimbal_Ctrl_Cmd_s));
|
||||
}
|
||||
|
||||
/* 机器人云台控制核心任务,后续考虑只保留IMU控制,不再需要电机的反馈 */
|
||||
void GimbalTask()
|
||||
{
|
||||
BuzzerOn();
|
||||
// 获取云台控制数据
|
||||
// 后续增加未收到数据的处理
|
||||
SubGetMessage(gimbal_sub, &gimbal_cmd_recv);
|
||||
// @todo:现在已不再需要电机反馈,实际上可以始终使用IMU的姿态数据来作为云台的反馈,yaw电机的offset只是用来跟随底盘
|
||||
// 根据控制模式进行电机反馈切换和过渡,视觉模式在robot_cmd模块就已经设置好,gimbal只看yaw_ref和pitch_ref
|
||||
switch (gimbal_cmd_recv.gimbal_mode)
|
||||
{
|
||||
// 停止
|
||||
case GIMBAL_ZERO_FORCE:
|
||||
DJIMotorStop(yaw_motor);
|
||||
DJIMotorStop(pitch_motor);
|
||||
break;
|
||||
// 使用陀螺仪的反馈,底盘根据yaw电机的offset跟随云台或视觉模式采用
|
||||
case GIMBAL_GYRO_MODE: // 后续只保留此模式
|
||||
// DJIMotorSetFeedfoward(yaw_motor,SPEED_FEEDFORWARD);
|
||||
DJIMotorEnable(yaw_motor);
|
||||
DJIMotorEnable(pitch_motor);
|
||||
DJIMotorChangeFeed(yaw_motor, ANGLE_LOOP, OTHER_FEED);
|
||||
DJIMotorChangeFeed(yaw_motor, SPEED_LOOP, OTHER_FEED);
|
||||
DJIMotorChangeFeed(pitch_motor, ANGLE_LOOP, OTHER_FEED);
|
||||
DJIMotorChangeFeed(pitch_motor, SPEED_LOOP, OTHER_FEED);
|
||||
DJIMotorSetRef(yaw_motor, gimbal_cmd_recv.yaw); // yaw和pitch会在robot_cmd中处理好多圈和单圈
|
||||
DJIMotorSetRef(pitch_motor, gimbal_cmd_recv.pitch);
|
||||
break;
|
||||
// 云台自由模式,使用编码器反馈,底盘和云台分离,仅云台旋转,一般用于调整云台姿态(英雄吊射等)/能量机关
|
||||
case GIMBAL_FREE_MODE: // 后续删除,或加入云台追地盘的跟随模式(响应速度更快)
|
||||
DJIMotorEnable(yaw_motor);
|
||||
DJIMotorEnable(pitch_motor);
|
||||
DJIMotorChangeFeed(yaw_motor, ANGLE_LOOP, OTHER_FEED);
|
||||
DJIMotorChangeFeed(yaw_motor, SPEED_LOOP, OTHER_FEED);
|
||||
DJIMotorChangeFeed(pitch_motor, ANGLE_LOOP, OTHER_FEED);
|
||||
DJIMotorChangeFeed(pitch_motor, SPEED_LOOP, OTHER_FEED);
|
||||
DJIMotorSetRef(yaw_motor, gimbal_cmd_recv.yaw); // yaw和pitch会在robot_cmd中处理好多圈和单圈
|
||||
DJIMotorSetRef(pitch_motor, gimbal_cmd_recv.pitch);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// 在合适的地方添加pitch重力补偿前馈力矩
|
||||
// 根据IMU姿态/pitch电机角度反馈计算出当前配重下的重力矩
|
||||
// ...
|
||||
|
||||
// 设置反馈数据,主要是imu和yaw的ecd
|
||||
gimbal_feedback_data.gimbal_imu_data = *gimba_IMU_data;
|
||||
gimbal_feedback_data.yaw_motor_single_round_angle = yaw_motor->measure.angle_single_round;
|
||||
|
||||
// 推送消息
|
||||
PubPushMessage(gimbal_pub, (void *)&gimbal_feedback_data);
|
||||
}
|
||||
@@ -19,14 +19,14 @@
|
||||
/* 开发板类型定义,烧录时注意不要弄错对应功能;修改定义后需要重新编译,只能存在一个定义! */
|
||||
// #define ONE_BOARD // 单板控制整车
|
||||
#define CHASSIS_BOARD //底盘板
|
||||
// #define GIMBAL_BOARD //云台板
|
||||
//#define GIMBAL_BOARD //云台板
|
||||
|
||||
#define VISION_USE_VCP // 使用虚拟串口发送视觉数据
|
||||
// #define VISION_USE_UART // 使用串口发送视觉数据
|
||||
|
||||
/* 机器人重要参数定义,注意根据不同机器人进行修改,浮点数需要以.0或f结尾,无符号以u结尾 */
|
||||
// 云台参数
|
||||
#define YAW_CHASSIS_ALIGN_ECD 2711 // 云台和底盘对齐指向相同方向时的电机编码器值,若对云台有机械改动需要修改
|
||||
#define YAW_CHASSIS_ALIGN_ECD 2716 // 云台和底盘对齐指向相同方向时的电机编码器值,若对云台有机械改动需要修改
|
||||
#define YAW_ECD_GREATER_THAN_4096 0 // ALIGN_ECD值是否大于4096,是为1,否为0;用于计算云台偏转角度
|
||||
#define PITCH_HORIZON_ECD 3412 // 云台处于水平位置时编码器值,若对云台有机械改动需要修改
|
||||
#define PITCH_MAX_ANGLE 0 // 云台竖直方向最大角度 (注意反馈如果是陀螺仪,则填写陀螺仪的角度)
|
||||
@@ -35,8 +35,8 @@
|
||||
// 发射参数
|
||||
#define ONE_BULLET_DELTA_ANGLE 36 // 发射一发弹丸拨盘转动的距离,由机械设计图纸给出
|
||||
#define REDUCTION_RATIO_LOADER 49.0f // 拨盘电机的减速比,英雄需要修改为3508的19.0f
|
||||
#define NUM_PER_CIRCLE 10 // 拨盘一圈的装载量
|
||||
|
||||
#define NUM_PER_CIRCLE 12 // 拨盘一圈的装载量
|
||||
#define LOAD_RATIO 2.5f //中心供弹需要机械减速比
|
||||
|
||||
#define GYRO2GIMBAL_DIR_YAW 1 // 陀螺仪数据相较于云台的yaw的方向,1为相同,-1为相反
|
||||
#define GYRO2GIMBAL_DIR_PITCH 1 // 陀螺仪数据相较于云台的pitch的方向,1为相同,-1为相反
|
||||
@@ -203,7 +203,7 @@ typedef struct
|
||||
|
||||
typedef struct
|
||||
{
|
||||
attitude_t gimbal_imu_data;
|
||||
INS_t gimbal_imu_data;
|
||||
uint16_t yaw_motor_single_round_angle;
|
||||
} Gimbal_Upload_Data_s;
|
||||
|
||||
|
||||
@@ -93,14 +93,12 @@ __attribute__((noreturn)) void StartDAEMONTASK(void const *argument)
|
||||
{
|
||||
static float daemon_dt;
|
||||
static float daemon_start;
|
||||
BuzzerInit();
|
||||
LOGINFO("[freeRTOS] Daemon Task Start");
|
||||
for (;;)
|
||||
{
|
||||
// 100Hz
|
||||
daemon_start = DWT_GetTimeline_ms();
|
||||
DaemonTask();
|
||||
BuzzerTask();
|
||||
daemon_dt = DWT_GetTimeline_ms() - daemon_start;
|
||||
if (daemon_dt > 10)
|
||||
LOGERROR("[freeRTOS] Daemon Task is being DELAY! dt = [%f]", &daemon_dt);
|
||||
|
||||
@@ -5,15 +5,203 @@
|
||||
#include "message_center.h"
|
||||
#include "bsp_dwt.h"
|
||||
#include "general_def.h"
|
||||
#include "servo_motor.h"
|
||||
/* 对于双发射机构的机器人,将下面的数据封装成结构体即可,生成两份shoot应用实例 */
|
||||
static DJIMotorInstance *friction_l; // 左摩擦轮
|
||||
static DJIMotorInstance *friction_r; // 右摩擦轮
|
||||
static DJIMotorInstance *loader; // 拨盘电机
|
||||
static ServoInstance *lid_L; //需要增加弹舱盖
|
||||
static ServoInstance *lid_R; //需要增加弹舱盖
|
||||
|
||||
static Publisher_t *shoot_pub;
|
||||
static Shoot_Ctrl_Cmd_s shoot_cmd_recv; // 来自gimbal_cmd的发射控制信息
|
||||
static Subscriber_t *shoot_sub;
|
||||
static Shoot_Upload_Data_s shoot_feedback_data; // 来自gimbal_cmd的发射控制信息
|
||||
|
||||
// dwt定时,计算冷却用
|
||||
static float hibernate_time = 0, dead_time = 0;
|
||||
static float load_angle_set = 0;
|
||||
void ShootInit()
|
||||
{
|
||||
// 左摩擦轮
|
||||
Motor_Init_Config_s friction_config = {
|
||||
.can_init_config = {
|
||||
.can_handle = &hcan2,
|
||||
},
|
||||
.controller_param_init_config = {
|
||||
.speed_PID = {
|
||||
.Kp = 1,//20
|
||||
.Ki = 0,//1
|
||||
.Kd = 0,
|
||||
.Derivative_LPF_RC = 0.02,
|
||||
.Improve = PID_Integral_Limit| PID_Trapezoid_Intergral | PID_DerivativeFilter,
|
||||
.IntegralLimit = 10000,
|
||||
.MaxOut = 15000,
|
||||
},
|
||||
.current_PID = {
|
||||
.Kp = 1.5,//0.7
|
||||
.Ki = 0,//0.1
|
||||
.Kd = 0,
|
||||
.Improve = PID_Integral_Limit,
|
||||
.IntegralLimit = 10000,
|
||||
.MaxOut = 15000,
|
||||
},
|
||||
|
||||
},
|
||||
.controller_setting_init_config = {
|
||||
.angle_feedback_source = MOTOR_FEED,
|
||||
.speed_feedback_source = MOTOR_FEED,
|
||||
|
||||
.outer_loop_type = SPEED_LOOP,
|
||||
.close_loop_type = SPEED_LOOP | CURRENT_LOOP ,
|
||||
.motor_reverse_flag = MOTOR_DIRECTION_NORMAL,
|
||||
|
||||
},
|
||||
.motor_type = M3508};
|
||||
friction_config.can_init_config.tx_id = 1,
|
||||
friction_l = DJIMotorInit(&friction_config);
|
||||
|
||||
friction_config.can_init_config.tx_id = 2; // 右摩擦轮,改txid和方向就行
|
||||
friction_config.controller_setting_init_config.motor_reverse_flag = MOTOR_DIRECTION_REVERSE;
|
||||
friction_r = DJIMotorInit(&friction_config);
|
||||
|
||||
// 拨盘电机
|
||||
Motor_Init_Config_s loader_config = {
|
||||
.can_init_config = {
|
||||
.can_handle = &hcan1,
|
||||
.tx_id = 3,
|
||||
},
|
||||
.controller_param_init_config = {
|
||||
.angle_PID = {
|
||||
// 如果启用位置环来控制发弹,需要较大的I值保证输出力矩的线性度否则出现接近拨出的力矩大幅下降
|
||||
.Kp = 10,//10
|
||||
.Ki = 0,
|
||||
.Kd = 0,
|
||||
.MaxOut = 20000,
|
||||
},
|
||||
.speed_PID = {
|
||||
.Kp = 0.5,//0
|
||||
.Ki = 0.1,//0
|
||||
.Kd = 0.002,
|
||||
.Improve = PID_Integral_Limit,
|
||||
.IntegralLimit = 200,
|
||||
.MaxOut = 10000,
|
||||
},
|
||||
.current_PID = {
|
||||
.Kp = 1.5,//0
|
||||
.Ki = 0,//0
|
||||
.Kd = 0,
|
||||
.Improve = PID_Integral_Limit,
|
||||
.IntegralLimit = 5000,
|
||||
.MaxOut = 10000,
|
||||
},
|
||||
},
|
||||
.controller_setting_init_config = {
|
||||
.angle_feedback_source = MOTOR_FEED, .speed_feedback_source = MOTOR_FEED,
|
||||
.outer_loop_type = SPEED_LOOP, // 初始化成SPEED_LOOP,让拨盘停在原地,防止拨盘上电时乱转
|
||||
.close_loop_type = SPEED_LOOP,
|
||||
.motor_reverse_flag = MOTOR_DIRECTION_NORMAL, // 注意方向设置为拨盘的拨出的击发方向
|
||||
},
|
||||
.motor_type = M2006 // 英雄使用m3508
|
||||
};
|
||||
loader = DJIMotorInit(&loader_config);
|
||||
|
||||
shoot_pub = PubRegister("shoot_feed", sizeof(Shoot_Upload_Data_s));
|
||||
shoot_sub = SubRegister("shoot_cmd", sizeof(Shoot_Ctrl_Cmd_s));
|
||||
}
|
||||
|
||||
/* 机器人发射机构控制核心任务 */
|
||||
void ShootTask()
|
||||
{
|
||||
// 从cmd获取控制数据
|
||||
SubGetMessage(shoot_sub, &shoot_cmd_recv);
|
||||
|
||||
// 对shoot mode等于SHOOT_STOP的情况特殊处理,直接停止所有电机(紧急停止)
|
||||
if (shoot_cmd_recv.shoot_mode == SHOOT_OFF)
|
||||
{
|
||||
DJIMotorStop(friction_l);
|
||||
DJIMotorStop(friction_r);
|
||||
DJIMotorStop(loader);
|
||||
}
|
||||
else // 恢复运行
|
||||
{
|
||||
DJIMotorEnable(friction_l);
|
||||
DJIMotorEnable(friction_r);
|
||||
DJIMotorEnable(loader);
|
||||
}
|
||||
if (shoot_cmd_recv.friction_mode == FRICTION_ON)
|
||||
{
|
||||
// 根据收到的弹速设置设定摩擦轮电机参考值,需实测后填入
|
||||
switch (shoot_cmd_recv.bullet_speed)
|
||||
{
|
||||
case SMALL_AMU_15:
|
||||
DJIMotorSetRef(friction_l, 26800);
|
||||
DJIMotorSetRef(friction_r, 26800);
|
||||
break;
|
||||
case SMALL_AMU_18:
|
||||
DJIMotorSetRef(friction_l, 30000);
|
||||
DJIMotorSetRef(friction_r, 30000);
|
||||
break;
|
||||
case SMALL_AMU_30:
|
||||
DJIMotorSetRef(friction_l, 46500);
|
||||
DJIMotorSetRef(friction_r, 46500);
|
||||
break;
|
||||
default: // 当前为了调试设定的默认值4000,因为还没有加入裁判系统无法读取弹速.
|
||||
DJIMotorSetRef(friction_l, 24500);
|
||||
DJIMotorSetRef(friction_r, 24500);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else // 关闭摩擦轮
|
||||
{
|
||||
DJIMotorSetRef(friction_l, 0);
|
||||
DJIMotorSetRef(friction_r, 0);
|
||||
}
|
||||
// 如果上一次触发单发或3发指令的时间加上不应期仍然大于当前时间(尚未休眠完毕),直接返回即可
|
||||
// 单发模式主要提供给能量机关激活使用(以及英雄的射击大部分处于单发)
|
||||
if (hibernate_time + dead_time > DWT_GetTimeline_ms())
|
||||
return;
|
||||
|
||||
|
||||
switch (shoot_cmd_recv.load_mode)
|
||||
{
|
||||
case LOAD_STOP:
|
||||
DJIMotorOuterLoop(loader, SPEED_LOOP); // 切换到速度环
|
||||
DJIMotorSetRef(loader, 0);
|
||||
break;
|
||||
// 单发模式,根据鼠标按下的时间,触发一次之后需要进入不响应输入的状态(否则按下的时间内可能多次进入,导致多次发射)
|
||||
case LOAD_1_BULLET: // 激活能量机关/干扰对方用,英雄用.
|
||||
load_angle_set = loader->measure.total_angle + ONE_BULLET_DELTA_ANGLE * 36;
|
||||
DJIMotorOuterLoop(loader, ANGLE_LOOP); // 切换到角度环
|
||||
DJIMotorSetRef(loader, load_angle_set); // 控制量增加一发弹丸的角度
|
||||
hibernate_time = DWT_GetTimeline_ms(); // 记录触发指令的时间
|
||||
dead_time = 500; // 完成1发弹丸发射的时间
|
||||
break;
|
||||
// 三连发,如果不需要后续可能删除
|
||||
case LOAD_3_BULLET:
|
||||
load_angle_set = loader->measure.total_angle + ONE_BULLET_DELTA_ANGLE * 36 *3 ;
|
||||
DJIMotorOuterLoop(loader, ANGLE_LOOP); // 切换到速度环
|
||||
DJIMotorSetRef(loader, load_angle_set); // 增加3发
|
||||
hibernate_time = DWT_GetTimeline_ms(); // 记录触发指令的时间
|
||||
dead_time = 1800; // 完成3发弹丸发射的时间
|
||||
break;
|
||||
// 连发模式,对速度闭环,射频后续修改为可变,目前固定为1Hz
|
||||
case LOAD_BURSTFIRE:
|
||||
DJIMotorOuterLoop(loader, SPEED_LOOP);
|
||||
DJIMotorSetRef(loader, shoot_cmd_recv.shoot_rate * 360 * REDUCTION_RATIO_LOADER * LOAD_RATIO/ NUM_PER_CIRCLE);
|
||||
// x颗/秒换算成速度: 已知一圈的载弹量,由此计算出1s需要转的角度,注意换算角速度(DJIMotor的速度单位是angle per second)
|
||||
break;
|
||||
// 拨盘反转,对速度闭环,后续增加卡弹检测(通过裁判系统剩余热量反馈和电机电流)
|
||||
// 也有可能需要从switch-case中独立出来
|
||||
case LOAD_REVERSE:
|
||||
DJIMotorOuterLoop(loader, SPEED_LOOP);
|
||||
// ...
|
||||
break;
|
||||
default:
|
||||
while (1)
|
||||
; // 未知模式,停止运行,检查指针越界,内存溢出等问题
|
||||
}
|
||||
|
||||
// 反馈数据,目前暂时没有要设定的反馈数据,后续可能增加应用离线监测以及卡弹反馈
|
||||
PubPushMessage(shoot_pub, (void *)&shoot_feedback_data);
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
#include "bsp_log.h"
|
||||
#include "bsp_dwt.h"
|
||||
#include "bsp_usb.h"
|
||||
|
||||
#include "buzzer.h"
|
||||
/**
|
||||
* @brief bsp层初始化统一入口,这里仅初始化必须的bsp组件,其他组件的初始化在各自的模块中进行
|
||||
* 需在实时系统启动前调用,目前由RobotoInit()调用
|
||||
@@ -17,6 +17,7 @@ void BSPInit()
|
||||
{
|
||||
DWT_Init(168);
|
||||
BSPLogInit();
|
||||
BuzzerInit();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,93 +1,31 @@
|
||||
#include "bsp_pwm.h"
|
||||
#include "buzzer.h"
|
||||
#include "bsp_dwt.h"
|
||||
#include "string.h"
|
||||
#include "main.h"
|
||||
|
||||
static PWMInstance *buzzer;
|
||||
// static uint8_t idx;
|
||||
static BuzzzerInstance *buzzer_list[BUZZER_DEVICE_CNT] = {0};
|
||||
extern TIM_HandleTypeDef htim4;
|
||||
static uint8_t tmp_warning_level = 0;
|
||||
|
||||
/**
|
||||
* @brief 蜂鸣器初始化
|
||||
*
|
||||
*/
|
||||
void BuzzerInit()
|
||||
{
|
||||
PWM_Init_Config_s buzzer_config = {
|
||||
.htim = &htim4,
|
||||
.channel = TIM_CHANNEL_3,
|
||||
.dutyratio = 0,
|
||||
.period = 0.001,
|
||||
};
|
||||
buzzer = PWMRegister(&buzzer_config);
|
||||
HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_3);
|
||||
__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_3, 0);
|
||||
}
|
||||
|
||||
BuzzzerInstance *BuzzerRegister(Buzzer_config_s *config)
|
||||
void BuzzerOn( )
|
||||
{
|
||||
if (config->alarm_level > BUZZER_DEVICE_CNT) // 超过最大实例数,考虑增加或查看是否有内存泄漏
|
||||
while (1)
|
||||
;
|
||||
BuzzzerInstance *buzzer_temp = (BuzzzerInstance *)malloc(sizeof(BuzzzerInstance));
|
||||
memset(buzzer_temp, 0, sizeof(BuzzzerInstance));
|
||||
|
||||
buzzer_temp->alarm_level = config->alarm_level;
|
||||
buzzer_temp->loudness = config->loudness;
|
||||
buzzer_temp->octave = config->octave;
|
||||
buzzer_temp->alarm_state = ALARM_OFF;
|
||||
|
||||
buzzer_list[config->alarm_level] = buzzer_temp;
|
||||
return buzzer_temp;
|
||||
}
|
||||
|
||||
void AlarmSetStatus(BuzzzerInstance *buzzer, AlarmState_e state)
|
||||
{
|
||||
buzzer->alarm_state = state;
|
||||
}
|
||||
|
||||
void BuzzerTask()
|
||||
{
|
||||
BuzzzerInstance *buzz;
|
||||
for (size_t i = 0; i < BUZZER_DEVICE_CNT; ++i)
|
||||
static int16_t temp = 4000 ;
|
||||
if(temp < 1000)
|
||||
{
|
||||
buzz = buzzer_list[i];
|
||||
if (buzz->alarm_level > ALARM_LEVEL_LOW)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (buzz->alarm_state == ALARM_OFF)
|
||||
{
|
||||
PWMSetDutyRatio(buzzer, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
PWMSetDutyRatio(buzzer, buzz->loudness);
|
||||
switch (buzz->octave)
|
||||
{
|
||||
case OCTAVE_1:
|
||||
PWMSetPeriod(buzzer, (float)1 / DoFreq);
|
||||
break;
|
||||
case OCTAVE_2:
|
||||
PWMSetPeriod(buzzer, (float)1 / ReFreq);
|
||||
break;
|
||||
case OCTAVE_3:
|
||||
PWMSetPeriod(buzzer, (float)1 / MiFreq);
|
||||
break;
|
||||
case OCTAVE_4:
|
||||
PWMSetPeriod(buzzer, (float)1 / FaFreq);
|
||||
break;
|
||||
case OCTAVE_5:
|
||||
PWMSetPeriod(buzzer, (float)1 / SoFreq);
|
||||
break;
|
||||
case OCTAVE_6:
|
||||
PWMSetPeriod(buzzer, (float)1 / LaFreq);
|
||||
break;
|
||||
case OCTAVE_7:
|
||||
PWMSetPeriod(buzzer, (float)1 / SiFreq);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
BuzzerOff();
|
||||
return;
|
||||
}
|
||||
__HAL_TIM_PRESCALER(&htim4,(int)(temp/1000));
|
||||
__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_3, 10000);
|
||||
temp -= 5 ;
|
||||
|
||||
}
|
||||
|
||||
void BuzzerOff(void)
|
||||
{
|
||||
__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_3, 0);
|
||||
tmp_warning_level = 0;
|
||||
}
|
||||
|
||||
@@ -1,60 +1,10 @@
|
||||
#ifndef BUZZER_H
|
||||
#define BUZZER_H
|
||||
#include "bsp_pwm.h"
|
||||
#define BUZZER_DEVICE_CNT 5
|
||||
|
||||
#define DoFreq 523
|
||||
#define ReFreq 587
|
||||
#define MiFreq 659
|
||||
#define FaFreq 698
|
||||
#define SoFreq 784
|
||||
#define LaFreq 880
|
||||
#define SiFreq 988
|
||||
|
||||
typedef enum
|
||||
{
|
||||
OCTAVE_1 = 0,
|
||||
OCTAVE_2,
|
||||
OCTAVE_3,
|
||||
OCTAVE_4,
|
||||
OCTAVE_5,
|
||||
OCTAVE_6,
|
||||
OCTAVE_7,
|
||||
OCTAVE_8,
|
||||
}octave_e;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ALARM_LEVEL_HIGH = 0,
|
||||
ALARM_LEVEL_ABOVE_MEDIUM,
|
||||
ALARM_LEVEL_MEDIUM,
|
||||
ALARM_LEVEL_BELOW_MEDIUM,
|
||||
ALARM_LEVEL_LOW,
|
||||
}AlarmLevel_e;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ALARM_OFF = 0,
|
||||
ALARM_ON,
|
||||
}AlarmState_e;
|
||||
typedef struct
|
||||
{
|
||||
AlarmLevel_e alarm_level;
|
||||
octave_e octave;
|
||||
float loudness;
|
||||
}Buzzer_config_s;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float loudness;
|
||||
octave_e octave;
|
||||
AlarmLevel_e alarm_level;
|
||||
AlarmState_e alarm_state;
|
||||
}BuzzzerInstance;
|
||||
#ifndef BSP_BUZZER_H
|
||||
#define BSP_BUZZER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void BuzzerInit();
|
||||
void BuzzerTask();
|
||||
BuzzzerInstance *BuzzerRegister(Buzzer_config_s *config);
|
||||
void AlarmSetStatus(BuzzzerInstance *buzzer, AlarmState_e state);
|
||||
#endif // !BUZZER_H
|
||||
extern void BuzzerOn();
|
||||
extern void BuzzerOff(void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -4,16 +4,21 @@
|
||||
#include "dji_motor.h"
|
||||
#include "step_motor.h"
|
||||
#include "servo_motor.h"
|
||||
|
||||
#include "dji_motor.h"
|
||||
#include "robot_def.h"
|
||||
void MotorControlTask()
|
||||
{
|
||||
// static uint8_t cnt = 0; 设定不同电机的任务频率
|
||||
// if(cnt%5==0) //200hz
|
||||
// if(cnt%10==0) //100hz
|
||||
// DJIMotorControl();
|
||||
|
||||
/* 如果有对应的电机则取消注释,可以加入条件编译或者register对应的idx判断是否注册了电机 */
|
||||
#ifdef GIMBAL_BOARD
|
||||
DJIMotorControl();
|
||||
#endif // DEBUG
|
||||
#ifdef CHASSIS_BOARD
|
||||
LKMotorControl();
|
||||
#endif // DEBUG
|
||||
/* 如果有对应的电机则取消注释,可以加入条件编译或者register对应的idx判断是否注册了电机 */
|
||||
//LKMotorControl();
|
||||
|
||||
// legacy support
|
||||
// 由于ht04电机的反馈方式为接收到一帧消息后立刻回传,以此方式连续发送可能导致总线拥塞
|
||||
|
||||
Reference in New Issue
Block a user