完成了底盘的框架,逆运动学解算和IMU融合尚未编写,也尚未对双板兼容条件编译进行设置,can未添加

This commit is contained in:
NeoZng
2022-12-04 13:49:08 +08:00
parent 78c9a77cf4
commit 92f376656c
12 changed files with 212 additions and 230 deletions

View File

@@ -1,35 +1,61 @@
/**
* @file chassis.c
* @author NeoZeng neozng1@hnu.edu.cn
* @brief 底盘应用,负责接收robot_cmd的控制命令并根据命令进行运动学解算,得到输出
* 注意底盘采取右手系,对于平面视图,底盘纵向运动的正前方为x正方向;横向运动的右侧为y正方向
*
* @version 0.1
* @date 2022-12-04
*
* @copyright Copyright (c) 2022
*
*/
#include "chassis.h"
#include "robot_def.h"
#include "dji_motor.h"
#include "super_cap.h"
#include "message_center.h"
#include "referee.h"
#include "arm_math.h"
#define OFFSET_X_CENTER //纵向轮距(前进后退方向)
#define OFFSET_Y_CENTER //横向轮距(左右平移方向)
#define RADIUS_WHEEL //轮子半径
#define PERIMETER_WHEEL
#define REDUCTION_RATIO 19
/* 需要根据机器人底盘修改的参数,单位为mm(毫米) */
#define WHEEL_BASE 300 // 纵向轴距(前进后退方向)
#define TRACK_WIDTH 300 // 横向轮距(左右平移方向)
#define CENTER_GIMBAL_OFFSET_X 0 // 云台旋转中心距底盘几何中心的距离,前后方向,云台位于正中心时默认设为0
#define CENTER_GIMBAL_OFFSET_Y 0 // 云台旋转中心距底盘几何中心的距离,左右方向,云台位于正中心时默认设为0
#define RADIUS_WHEEL 60 // 轮子半径
#define REDUCTION_RATIO 19 // 电机减速比,因为编码器量测的是转子的速度而不是输出轴的速度故需进行转换
/* 底盘应用包含的模块和信息存储 */
#ifdef CHASSIS_BOARD // 使用板载IMU获取底盘转动角速度
/* 自动计算的参数 */
#define HALF_WHEEL_BASE (WHEEL_BASE / 2.0f)
#define HALF_TRACK_WIDTH (TRACK_WIDTH / 2.0f)
#define PERIMETER_WHEEL (RADIUS_WHEEL * 2 * PI)
/* 底盘应用包含的模块和信息存储,底盘是单例模式,因此不需要为底盘建立单独的结构体 */
#ifdef CHASSIS_BOARD // 如果是底盘板,使用板载IMU获取底盘转动角速度
#include "can_comm.h"
#include "ins_task.h"
static CANCommInstance *chasiss_can_comm; // 双板通信CAN comm
IMU_Data_t *Chassis_IMU_data;
#endif // CHASSIS_BOARD
// static SuperCAP cap;
static dji_motor_instance *lf; // left right forward back
static dji_motor_instance *rf;
static dji_motor_instance *lb;
static dji_motor_instance *rb;
static referee_info_t *referee_data; // 裁判系统的数据
// static SuperCAP* cap; 尚未增加超级电容
static dji_motor_instance *motor_lf; // left right forward back
static dji_motor_instance *motor_rf;
static dji_motor_instance *motor_lb;
static dji_motor_instance *motor_rb;
static Publisher_t* chassis_pub;
/* chassis 包含的信息交互模块和数据*/
static Publisher_t *chassis_pub;
static Chassis_Ctrl_Cmd_s chassis_cmd_recv;
static Subscriber_t* chassis_sub;
static Subscriber_t *chassis_sub;
static Chassis_Upload_Data_s chassis_feedback_data;
// 将云台系的速度投影到底盘
static float chassis_vx,chassis_vy;
/* 私有函数计算的中介变量,设为静态避免参数传递的开销 */
static float chassis_vx, chassis_vy; // 将云台系的速度投影到底盘
static float vt_lf, vt_rf, vt_lb, vt_rb; // 底盘速度解算后的临时输出,待进行限幅
void ChassisInit()
{
@@ -40,11 +66,6 @@ void ChassisInit()
.tx_id = 1,
},
.controller_param_init_config = {
.angle_PID = {
.Kd = 10,
.Ki = 1,
.Kd = 2,
},
.speed_PID = {
},
@@ -66,11 +87,6 @@ void ChassisInit()
.tx_id = 2,
},
.controller_param_init_config = {
.angle_PID = {
.Kd = 10,
.Ki = 1,
.Kd = 2,
},
.speed_PID = {
},
@@ -92,11 +108,6 @@ void ChassisInit()
.tx_id = 3,
},
.controller_param_init_config = {
.angle_PID = {
.Kd = 10,
.Ki = 1,
.Kd = 2,
},
.speed_PID = {
},
@@ -118,11 +129,6 @@ void ChassisInit()
.tx_id = 4,
},
.controller_param_init_config = {
.angle_PID = {
.Kd = 10,
.Ki = 1,
.Kd = 2,
},
.speed_PID = {
},
@@ -138,74 +144,113 @@ void ChassisInit()
},
.motor_type = M3508};
lf = DJIMotorInit(&left_foward_config);
rf = DJIMotorInit(&right_foward_config);
lb = DJIMotorInit(&left_back_config);
rb = DJIMotorInit(&right_back_config);
motor_lf = DJIMotorInit(&left_foward_config);
motor_rf = DJIMotorInit(&right_foward_config);
motor_lb = DJIMotorInit(&left_back_config);
motor_rb = DJIMotorInit(&right_back_config);
referee_data = RefereeInit(&huart6);
// SupercapInit();
chassis_sub=SubRegister("chassis_cmd",sizeof(Chassis_Ctrl_Cmd_s));
chassis_pub=PubRegister("chassis_feed",sizeof(Chassis_Upload_Data_s));
chassis_sub = SubRegister("chassis_cmd", sizeof(Chassis_Ctrl_Cmd_s));
chassis_pub = PubRegister("chassis_feed", sizeof(Chassis_Upload_Data_s));
}
#define LF_CENTER ((HALF_TRACK_WIDTH + CENTER_GIMBAL_OFFSET_X + HALF_WHEEL_BASE - CENTER_GIMBAL_OFFSET_Y) * ANGLE_2_RAD)
#define RF_CENTER ((HALF_TRACK_WIDTH - CENTER_GIMBAL_OFFSET_X + HALF_WHEEL_BASE - CENTER_GIMBAL_OFFSET_Y) * ANGLE_2_RAD)
#define LB_CENTER ((HALF_TRACK_WIDTH + CENTER_GIMBAL_OFFSET_X + HALF_WHEEL_BASE + CENTER_GIMBAL_OFFSET_Y) * ANGLE_2_RAD)
#define RB_CENTER ((HALF_TRACK_WIDTH - CENTER_GIMBAL_OFFSET_X + HALF_WHEEL_BASE + CENTER_GIMBAL_OFFSET_Y) * ANGLE_2_RAD)
/**
* @brief 计算每个轮毂电机的输出,正运动学解算
*
* 用宏进行预替换减小开销
*/
static void MecanumCalculate()
{
vt_lf = -chassis_vx - chassis_vy - chassis_cmd_recv.wz * LF_CENTER;
vt_rf = -chassis_vx + chassis_vy - chassis_cmd_recv.wz * RF_CENTER;
vt_lb = chassis_vx + chassis_vy - chassis_cmd_recv.wz * LB_CENTER;
vt_rb = chassis_vx - chassis_vy - chassis_cmd_recv.wz * RB_CENTER;
}
/**
* @brief 根据裁判系统和电容剩余容量对输出进行限制并设置电机参考值
*
*/
static void LimitChassisOutput()
{
// 限制待添加
// referee_data->PowerHeatData.chassis_power;
// referee_data->PowerHeatData.chassis_power_buffer;
DJIMotorSetRef(motor_lf, vt_lf);
DJIMotorSetRef(motor_rf, vt_rf);
DJIMotorSetRef(motor_lb, vt_lb);
DJIMotorSetRef(motor_rb, vt_rb);
}
/**
* @brief 根据每个轮子的速度反馈,计算底盘的实际运动速度,逆运动解算
*
* 对于双板的情况,考虑增加来自底盘板IMU的数据
*
*/
static void EstimateSpeed()
{
// 根据电机速度和imu的速度解算
// chassis_feedback_data.vx vy wz
// ...
}
// chassis_cmd_recv chassis_feedback_data
void ChassisTask()
{
// 后续增加没收到消息的处理
// 获取新的控制信息
SubGetMessage(chassis_sub,&chassis_cmd_recv);
SubGetMessage(chassis_sub, &chassis_cmd_recv);
if(chassis_cmd_recv.chassis_cmd.chassis_mode==CHASSIS_ZERO_FORCE)
// 如果出现重要模块离线或遥控器设置为急停,让电机停止
if (chassis_cmd_recv.chassis_mode == CHASSIS_ZERO_FORCE)
{
DJIMotorStop();
}
// 根据云台和底盘的角度offset将控制量映射到底盘坐标系上
chassis_vx=chassis_cmd_recv.chassis_cmd.vx*arm_cos_f32(chassis_cmd_recv.chassis_cmd.offset_angle)-
chassis_cmd_recv.chassis_cmd.vy*arm_sin_f32(chassis_cmd_recv.chassis_cmd.offset_angle);
chassis_vy=chassis_cmd_recv.chassis_cmd.vx*arm_sin_f32(chassis_cmd_recv.chassis_cmd.offset_angle)-
chassis_cmd_recv.chassis_cmd.vy*arm_cos_f32(chassis_cmd_recv.chassis_cmd.offset_angle);
// 底盘逆时针旋转为角度正方向;云台命令的方向以云台指向的方向为x,采用右手系(x指向正北时y在正东)
chassis_vx = chassis_cmd_recv.vx * arm_cos_f32(chassis_cmd_recv.offset_angle) -
chassis_cmd_recv.vy * arm_sin_f32(chassis_cmd_recv.offset_angle);
chassis_vy = chassis_cmd_recv.vx * arm_sin_f32(chassis_cmd_recv.offset_angle) -
chassis_cmd_recv.vy * arm_cos_f32(chassis_cmd_recv.offset_angle);
// 根据控制模式设定旋转速度
switch (chassis_cmd_recv.chassis_cmd.chassis_mode)
switch (chassis_cmd_recv.chassis_mode)
{
case CHASSIS_NO_FOLLOW:
chassis_cmd_recv.chassis_cmd.wz=0;
chassis_cmd_recv.wz = 0; // 云台任意移动模式,不旋转,一般用于调整云台姿态
break;
case CHASSIS_FOLLOW_GIMBAL_YAW:
chassis_cmd_recv.chassis_cmd.wz=0.05f*powf(chassis_cmd_recv.chassis_cmd.wz,2.0f); // 不开pid,以误差角平方为输出
chassis_cmd_recv.wz = 0.05f * powf(chassis_cmd_recv.wz, 2.0f); // 跟随,不开pid,以误差角平方为输出
break;
case CHASSIS_ROTATE:
//chassis_cmd_recv.chassis_cmd.wz 当前维持定值,后续增加不规则的变速策略
// chassis_cmd_recv.wz // 当前维持定值,后续增加不规则的变速策略
break;
default:
break;
}
//根据控制模式进行正运动学解算,计算底盘输出
// 根据控制模式进行正运动学解算,计算底盘输出
MecanumCalculate();
//根据电机的反馈速度计算
// 根据裁判系统的反馈数据和电容数据对输出限幅
LimitChassisOutput();
// 根据电机的反馈速度计算
EstimateSpeed();
PubPushMessage(chassis_pub,&chassis_feedback_data);
//获取裁判系统数据
// 我方颜色id小于7是红色,大于7是蓝色,注意这里发送的是对方的颜色, 0:blue , 1:red
chassis_feedback_data.enemy_color = referee_data->GameRobotStat.robot_id > 7 ? 1 : 0; //
chassis_feedback_data.bullet_speed = referee_data->GameRobotStat.shooter_id1_17mm_speed_limit;
chassis_feedback_data.rest_heat=referee_data->PowerHeatData.shooter_heat0;
// 推送反馈消息
PubPushMessage(chassis_pub, &chassis_feedback_data);
}

View File

@@ -1,40 +0,0 @@
#include "robot_def.h"
#include "chassis_cmd.h"
#include "referee.h"
#include "message_center.h"
/* chassis_cmd应用包含的模块和信息存储 */
static referee_info_t *referee_data; // 裁判系统的数据
#ifndef ONE_BOARD
#include "can_comm.h"
static CANCommInstance *chasiss_can_comm; // 双板通信CAN comm
#endif // !ONE_BOARD
//和chassis应用的交互
static Publisher_t* chassis_cmd_pub;
static Chassis_Ctrl_Cmd_s chassis_cmd; // 发送给chassis应用的控制信息
static Subscriber_t* chassis_feed_sub;
static Chassis_Upload_Data_s chassis_fetch_data; // chassis反馈的数据
//和gimbal_cmd的交互
static Publisher_t* chassis2gimbal_pub;
static Chassis2Gimbal_Data_s data_to_gimbal_cmd; // 发送给gimbal_cmd的数据,包括热量限制,底盘功率等
static Subscriber_t* gimbal2chassis_sub;
static Gimbal2Chassis_Data_s data_from_gimbal_cmd; // 来自gimbal_cmd的数据,主要是底盘控制量
void ChassisCMDInit()
{
referee_data= RefereeInit(&huart6);
chassis_cmd_pub=PubRegister("chassis_cmd",sizeof(Chassis_Ctrl_Cmd_s));
chassis_feed_sub=SubRegister("chassis_feed",sizeof(Chassis_Upload_Data_s));
chassis2gimbal_pub=PubRegister("chassis2gimbal",sizeof(Chassis2Gimbal_Data_s));
gimbal2chassis_sub=SubRegister("gimbal2chassis",sizeof(Gimbal2Chassis_Data_s));
}
void ChassisCMDTask()
{
SubGetMessage(chassis_feed_sub,&chassis_fetch_data);
SubGetMessage(gimbal2chassis_sub,&data_from_gimbal_cmd);
}

View File

@@ -1,8 +0,0 @@
#ifndef CHASSIS_CMD_H
#define CHASSIS_CMD_H
void ChassisCMDInit();
void ChassisCMDTask();
#endif // !CHASSIS_CMD_H

View File

@@ -1,65 +0,0 @@
#include "robot_def.h"
#include "gimbal_cmd.h"
#include "remote_control.h"
#include "ins_task.h"
#include "master_process.h"
#include "message_center.h"
/* gimbal_cmd应用包含的模块实例指针和交互信息存储*/
#ifndef ONE_BOARD
#include "can_comm.h"
static CANCommInstance *chasiss_can_comm; //双板通信
#endif // !ONE_BOARD
static RC_ctrl_t *remote_control_data; // 遥控器数据
static Vision_Recv_s *vision_recv_data; // 视觉接收数据
static Vision_Send_s *vision_send_data; // 视觉发送数据
static Publisher_t* gimbal_cmd_pub;
static Gimbal_Ctrl_Cmd_s gimbal_cmd_send; // 传递给云台的控制信息
static Subscriber_t* gimbal_cmd_feed_sub;
static Gimbal_Upload_Data_s gimbal_fetch_data; // 从云台获取的反馈信息
static Publisher_t* shoot_cmd_pub;
static Shoot_Ctrl_Cmd_s shoot_cmd_send; // 传递给发射的控制信息
static Subscriber_t* shoot_cmd_feed_sub;
static Shoot_Upload_Data_s shoot_fetch_data; // 从发射获取的反馈信息
static Publisher_t* gimbal2chassis_pub;
static Gimbal2Chassis_Data_s data_to_chassis_cmd; // 发送给底盘CMD应用的控制信息,主要是遥控器和UI绘制相关
static Subscriber_t* chassis2gimbal_sub;
static Chassis2Gimbal_Data_s data_from_chassis_cmd; // 从底盘CMD应用接收的控制信息,底盘功率枪口热量等
static void CalcOffsetAngle()
{
}
static void SetRobotMode()
{
}
static void SetCtrlData()
{
}
static void SetCtrlMessage()
{
}
void GimbalCMDInit()
{
remote_control_data=RC_init(&huart3);
vision_recv_data=VisionInit(&huart1);
gimbal_cmd_pub=PubRegister("gimbal_cmd",sizeof(Gimbal_Ctrl_Cmd_s));
gimbal_cmd_feed_sub=SubRegister("gimbal_feed",sizeof(Gimbal_Upload_Data_s));
shoot_cmd_pub=PubRegister("shoot_cmd",sizeof(Shoot_Ctrl_Cmd_s));
shoot_cmd_feed_sub=SubRegister("shoot_feed",sizeof(Shoot_Upload_Data_s));
gimbal2chassis_pub=PubRegister("gimbal2chassis",sizeof(Gimbal2Chassis_Data_s));
chassis2gimbal_sub=SubRegister("chassis2gimbal",sizeof(Chassis2Gimbal_Data_s));
}
void GimbalCMDTask()
{
}

View File

@@ -0,0 +1,63 @@
#include "robot_def.h"
#include "robot_cmd.h"
#include "remote_control.h"
#include "ins_task.h"
#include "master_process.h"
#include "message_center.h"
/* gimbal_cmd应用包含的模块实例指针和交互信息存储*/
#ifndef ONE_BOARD
#include "can_comm.h"
static CANCommInstance *chasiss_can_comm; // 双板通信
#endif // !ONE_BOARD
static RC_ctrl_t *remote_control_data; // 遥控器数据
static Vision_Recv_s *vision_recv_data; // 视觉接收数据
static Vision_Send_s *vision_send_data; // 视觉发送数据
static Publisher_t *gimbal_cmd_pub;
static Gimbal_Ctrl_Cmd_s gimbal_cmd_send; // 传递给云台的控制信息
static Subscriber_t *gimbal_cmd_feed_sub;
static Gimbal_Upload_Data_s gimbal_fetch_data; // 从云台获取的反馈信息
static Publisher_t *shoot_cmd_pub;
static Shoot_Ctrl_Cmd_s shoot_cmd_send; // 传递给发射的控制信息
static Subscriber_t *shoot_cmd_feed_sub;
static Shoot_Upload_Data_s shoot_fetch_data; // 从发射获取的反馈信息
static Publisher_t *chassis_cmd_pub;
static Chassis_Ctrl_Cmd_s chassis_cmd_send; // 发送给底盘应用的信息,包括控制信息和UI绘制相关
static Subscriber_t *chassis_cmd_feed_sub;
static Chassis_Upload_Data_s chassis_fetch_data; // 从底盘应用接收的反馈信息信息,底盘功率枪口热量与底盘运动状态等
static void CalcOffsetAngle()
{
}
static void SetRobotMode()
{
}
static void SetCtrlData()
{
}
static void SetCtrlMessage()
{
}
void GimbalCMDInit()
{
remote_control_data = RC_init(&huart3);
vision_recv_data = VisionInit(&huart1);
gimbal_cmd_pub = PubRegister("gimbal_cmd", sizeof(Gimbal_Ctrl_Cmd_s));
gimbal_cmd_feed_sub = SubRegister("gimbal_feed", sizeof(Gimbal_Upload_Data_s));
shoot_cmd_pub = PubRegister("shoot_cmd", sizeof(Shoot_Ctrl_Cmd_s));
shoot_cmd_feed_sub = SubRegister("shoot_feed", sizeof(Shoot_Upload_Data_s));
chassis_cmd_pub = PubRegister("gimbal2chassis", sizeof(Chassis_Ctrl_Cmd_s));
chassis_cmd_feed_sub = SubRegister("chassis2gimbal", sizeof(Chassis_Upload_Data_s));
}
void GimbalCMDTask()
{
}

View File

View File

@@ -3,40 +3,35 @@
#if defined(ONE_BOARD) || defined(CHASSIS_BOARD)
#include "chassis.h"
#include "chassis_cmd.h"
#endif
#endif
#if defined(ONE_BOARD) || defined(GIMBAL_BOARD)
#include "gimbal.h"
#include "shoot.h"
#include "gimbal_cmd.h"
#endif
#include "robot_cmd.h"
#endif
void RobotInit()
{
#if defined(ONE_BOARD) || defined(CHASSIS_BOARD)
ChassisInit();
ChassisCMDInit();
#endif
#endif
#if defined(ONE_BOARD) || defined(GIMBAL_BOARD)
GimbalCMDInit();
GimbalInit();
ShootInit();
#endif
#endif
}
void RobotTask()
{
#if defined(ONE_BOARD) || defined(CHASSIS_BOARD)
ChassisTask();
ChassisCMDTask();
#endif
#endif
#if defined(ONE_BOARD) || defined(GIMBAL_BOARD)
GimbalCMDTask();
GimbalTask();
ShootTask();
#endif
#endif
}

View File

@@ -12,6 +12,10 @@
#ifndef ROBOT_DEF_H
#define ROBOT_DEF_H
#define PI 3.14159f
#define RAD_2_ANGLE (180.0f/PI)
#define ANGLE_2_RAD (PI/180.0f)
#include "ins_task.h"
#include "master_process.h"
#include "stdint-gcc.h"
@@ -25,6 +29,7 @@
/* 重要参数定义,注意根据不同机器人进行修改 */
#define YAW_MID_ECD
#if (defined(ONE_BOARD) && defined(CHASSIS_BOARD)) || \
(defined(ONE_BOARD) && defined(GIMBAL_BOARD)) || \
(defined(CHASSIS_BOARD) && defined(GIMBAL_BOARD))
@@ -90,57 +95,34 @@ typedef enum
// 功率限制,从裁判系统获取
typedef struct
{ // 功率控制
uint8_t power_limit;
uint8_t buffer_power_rest;
} Chassis_Power_Data_s;
/* ------------CMD模块之间的控制数据传递,应当由gimbal_cmd和chassis_cmd订阅------------ */
/**
* @brief 对于双板通信的情况,两个CMD模块各有一个can comm.
*
*/
// gimbal_cmd发布的底盘控制数据,由chassis_cmd订阅
// 注意这里没有功率限制,为了兼容双板模式,先让chassis_cmd订阅,后者会添加功率信息再发布
typedef struct
{
// 速度控制
float vx; // 前进方向速度
float vy; // 横移方向速度
float wz; // 旋转速度
float offset_angle; // 底盘和归中位置的夹角
chassis_mode_e chassis_mode;
} Gimbal2Chassis_Data_s;
// chassis_cmd发布的裁判系统和底盘信息相关的数据,由gimbal_cmd订阅
typedef struct
{
float chassis_real_rotate_wz;
uint8_t rest_heat;
Bullet_Speed_e bullet_speed;
Enemy_Color_e enemy_color; // 0 for blue, 1 for red
} Chassis2Gimbal_Data_s;
/* ----------------CMD应用发布的控制数据,应当由gimbal/chassis/shoot订阅---------------- */
/**
* @brief 对于双板情况,遥控器和pc在云台,裁判系统在底盘
*
*/
// chassis_cmd根据raw ctrl data添加功率限制后发布的底盘控制数据,由chassis订阅
// cmd发布的底盘控制数据,由chassis订阅
typedef struct
{
Chassis_Power_Data_s chassis_power;
Gimbal2Chassis_Data_s chassis_cmd;
// 控制部分
float vx; // 前进方向速度
float vy; // 横移方向速度
float wz; // 旋转速度
float offset_angle; // 底盘和归中位置的夹角
chassis_mode_e chassis_mode;
//UI部分
// ...
} Chassis_Ctrl_Cmd_s;
// gimbal_cmd发布的云台控制数据,由gimbal订阅
// cmd发布的云台控制数据,由gimbal订阅
typedef struct
{ // 云台角度控制
float yaw;
@@ -150,7 +132,7 @@ typedef struct
gimbal_mode_e gimbal_mode;
} Gimbal_Ctrl_Cmd_s;
// gimba_cmd发布的发射控制数据,由shoot订阅
// cmd发布的发射控制数据,由shoot订阅
typedef struct
{ // 发射弹速控制
loader_mode_e load_mode;
@@ -174,6 +156,18 @@ typedef struct
#ifdef CHASSIS_BOARD
attitude_t chassis_imu_data;
#endif // CHASSIS_BOARD
// 后续增加底盘的真实速度
// float real_vx;
// float real_vy;
// float real_wz;
uint8_t rest_heat; //剩余枪口热量
Bullet_Speed_e bullet_speed; //弹速限制
Enemy_Color_e enemy_color; // 0 for blue, 1 for red
//是否需要剩余电量?(电容)
} Chassis_Upload_Data_s;
typedef struct