mirror of
https://gitee.com/dlmu-cone/half-steering-basic-framework
synced 2026-10-23 17:42:20 +08:00
Compare commits
49 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2b18d60476 | ||
|
|
72df1a2654 | ||
|
|
428956e3bd | ||
|
|
214971c58b | ||
|
|
194047605d | ||
|
|
dc1152e186 | ||
|
|
90bdda348e | ||
|
|
e8f4bf3cf2 | ||
|
|
e783abf8d6 | ||
|
|
579b507e3b | ||
|
|
f8282c80b9 | ||
|
|
47aba369d8 | ||
|
|
be8f3f38c8 | ||
|
|
8e1e2455e0 | ||
|
|
e66dbb8052 | ||
|
|
a6c7ccd2a1 | ||
|
|
3d7a4592c4 | ||
|
|
99bfe7cec7 | ||
|
|
69b407db26 | ||
|
|
d1d5698c13 | ||
|
|
31ffd2bde4 | ||
|
|
b660cbb9f9 | ||
|
|
772ce14ae6 | ||
|
|
0eae0777ca | ||
|
|
300048362f | ||
|
|
1f4e8d85b9 | ||
|
|
b355992730 | ||
|
|
e8dde8b825 | ||
|
|
df0e1f4b1f | ||
|
|
277b3a11c0 | ||
|
|
9e7faaca8b | ||
|
|
43b724d7b7 | ||
|
|
a61ed6ff25 | ||
|
|
31eef65a6d | ||
|
|
0235c428c5 | ||
|
|
4b17e1e193 | ||
|
|
9d4e103a01 | ||
|
|
082bf3199a | ||
|
|
3add7c5eb2 | ||
|
|
bd9314aa7a | ||
|
|
dc0d98d0a6 | ||
|
|
d3c9c04c2a | ||
|
|
933e86e1bb | ||
|
|
1a537d7f79 | ||
| 42c26fa8ac | |||
| d6c91d7b6f | |||
| 24d718a755 | |||
| a541614346 | |||
| 351dfc6b71 |
@@ -46,7 +46,7 @@ void MX_USART1_UART_Init(void)
|
|||||||
|
|
||||||
/* USER CODE END USART1_Init 1 */
|
/* USER CODE END USART1_Init 1 */
|
||||||
huart1.Instance = USART1;
|
huart1.Instance = USART1;
|
||||||
huart1.Init.BaudRate = 921600;
|
huart1.Init.BaudRate = 115200;
|
||||||
huart1.Init.WordLength = UART_WORDLENGTH_8B;
|
huart1.Init.WordLength = UART_WORDLENGTH_8B;
|
||||||
huart1.Init.StopBits = UART_STOPBITS_1;
|
huart1.Init.StopBits = UART_STOPBITS_1;
|
||||||
huart1.Init.Parity = UART_PARITY_NONE;
|
huart1.Init.Parity = UART_PARITY_NONE;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @file chassis.c
|
* @file chassis.c
|
||||||
* @author NeoZeng neozng1@hnu.edu.cn
|
* @author NeoZeng neozng1@hnu.edu.cn
|
||||||
@@ -30,9 +31,10 @@
|
|||||||
#define HALF_TRACK_WIDTH (TRACK_WIDTH / 2.0f) // 半轮距
|
#define HALF_TRACK_WIDTH (TRACK_WIDTH / 2.0f) // 半轮距
|
||||||
#define PERIMETER_WHEEL (RADIUS_WHEEL * 2 * PI) // 轮子周长
|
#define PERIMETER_WHEEL (RADIUS_WHEEL * 2 * PI) // 轮子周长
|
||||||
#if defined(CHASSIS_MCNAMEE_WHEEL)
|
#if defined(CHASSIS_MCNAMEE_WHEEL)
|
||||||
#define CHASSIS_WHEEL_OFFSET 1.0f // 机器人底盘轮子修正偏移量
|
//#define CHASSIS_WHEEL_OFFSET 1.0f // 机器人底盘轮子修正偏移量
|
||||||
#elif defined(CHASSIS_STEERING_WHEEL)
|
#elif defined(CHASSIS_STEERING_WHEEL)
|
||||||
#define CHASSIS_WHEEL_OFFSET 30.0f // 机器人底盘轮子修正偏移量
|
#define CHASSIS_WHEEL_OFFSET 30.0f // 机器人底盘轮子修正偏移量
|
||||||
|
//#define CHASSIS_WHEEL_OFFSET 2.0f
|
||||||
#define SQRT2 1.41421356f // 根号2
|
#define SQRT2 1.41421356f // 根号2
|
||||||
#elif defined(CHASSIS_OMNI_WHEEL)
|
#elif defined(CHASSIS_OMNI_WHEEL)
|
||||||
#define CHASSIS_WHEEL_OFFSET 0.7071f // 机器人底盘轮子修正偏移量,根号2/2,即45度,用于修正全向轮的安装位置
|
#define CHASSIS_WHEEL_OFFSET 0.7071f // 机器人底盘轮子修正偏移量,根号2/2,即45度,用于修正全向轮的安装位置
|
||||||
@@ -53,18 +55,18 @@ static Chassis_Ctrl_Cmd_s chassis_cmd_recv; // 底盘接收到的控制
|
|||||||
static Chassis_Upload_Data_s chassis_feedback_data; // 底盘回传的反馈数据
|
static Chassis_Upload_Data_s chassis_feedback_data; // 底盘回传的反馈数据
|
||||||
|
|
||||||
static referee_info_t* referee_data; // 用于获取裁判系统的数据
|
static referee_info_t* referee_data; // 用于获取裁判系统的数据
|
||||||
static Referee_Interactive_info_t ui_data; // UI数据,将底盘中的数据传入此结构体的对应变量中,UI会自动检测是否变化,对应显示UI
|
static Referee_Interactive_info_t ui_data; // UI数据,将底盘中的数据传入此结构体的对应变量中,UI会自动检测是否变化,对应显示UI/
|
||||||
|
|
||||||
static SuperCapInstance *cap; // 超级电容
|
static SuperCapInstance *cap; // 超级电容
|
||||||
static LKMotorInstance *motor_lb,*motor_rf; // 轮电机9015
|
static LKMotorInstance *motor_rf,*motor_lb; // 轮电机9015
|
||||||
static DJIMotorInstance *motor_steering_lb,*motor_steering_rf; // 舵电机6020
|
static DJIMotorInstance *motor_steering_rf,*motor_steering_lb; // 舵电机6020
|
||||||
/* 用于自旋变速策略的时间变量 */
|
/* 用于自旋变速策略的时间变量 */
|
||||||
// static float t;
|
// static float t;
|
||||||
|
|
||||||
/* 私有函数计算的中介变量,设为静态避免参数传递的开销 */
|
/* 私有函数计算的中介变量,设为静态避免参数传递的开销 */
|
||||||
static float chassis_vx, chassis_vy; // 将云台系的速度投影到底盘
|
static float chassis_vx, chassis_vy; // 将云台系的速度投影到底盘
|
||||||
static float vt_lb, vt_rf; // 底盘速度解算后的临时输出,待进行限幅
|
static float vt_rf, vt_lb; // 底盘速度解算后的临时输出,待进行限幅
|
||||||
static float at_lb, at_rf; // 底盘的角度解算后的临时输出,待进行限幅
|
static float at_rf, at_lb; // 底盘的角度解算后的临时输出,待进行限幅
|
||||||
static PIDInstance chassis_follow_pid; // 底盘跟随云台的PID
|
static PIDInstance chassis_follow_pid; // 底盘跟随云台的PID
|
||||||
|
|
||||||
void ChassisInit()
|
void ChassisInit()
|
||||||
@@ -82,7 +84,7 @@ void ChassisInit()
|
|||||||
.MaxOut = 12000,
|
.MaxOut = 12000,
|
||||||
},
|
},
|
||||||
.current_PID = {
|
.current_PID = {
|
||||||
.Kp = 1, // 0.4
|
.Kp = 0.4, // 0.4
|
||||||
.Ki = 0, // 0
|
.Ki = 0, // 0
|
||||||
.Kd = 0,
|
.Kd = 0,
|
||||||
.IntegralLimit = 10500,
|
.IntegralLimit = 10500,
|
||||||
@@ -102,11 +104,11 @@ void ChassisInit()
|
|||||||
|
|
||||||
chassis_motor_config.can_init_config.tx_id = 1;
|
chassis_motor_config.can_init_config.tx_id = 1;
|
||||||
// chassis_motor_config.controller_setting_init_config.motor_reverse_flag = MOTOR_DIRECTION_REVERSE;
|
// chassis_motor_config.controller_setting_init_config.motor_reverse_flag = MOTOR_DIRECTION_REVERSE;
|
||||||
motor_rf = LKMotorInit(&chassis_motor_config);
|
motor_lb= LKMotorInit(&chassis_motor_config);
|
||||||
|
|
||||||
chassis_motor_config.can_init_config.tx_id = 2;
|
chassis_motor_config.can_init_config.tx_id = 2;
|
||||||
// chassis_motor_config.controller_setting_init_config.motor_reverse_flag = MOTOR_DIRECTION_REVERSE;
|
// chassis_motor_config.controller_setting_init_config.motor_reverse_flag = MOTOR_DIRECTION_REVERSE;
|
||||||
motor_lb = LKMotorInit(&chassis_motor_config);
|
motor_rf = LKMotorInit(&chassis_motor_config);
|
||||||
|
|
||||||
// 舵电机6020初始化
|
// 舵电机6020初始化
|
||||||
Motor_Init_Config_s chassis_motor_steering_config = {
|
Motor_Init_Config_s chassis_motor_steering_config = {
|
||||||
@@ -144,22 +146,22 @@ void ChassisInit()
|
|||||||
.motor_type = GM6020,
|
.motor_type = GM6020,
|
||||||
};
|
};
|
||||||
|
|
||||||
chassis_motor_steering_config.can_init_config.tx_id = 1;
|
chassis_motor_steering_config.can_init_config.tx_id = 2;
|
||||||
motor_steering_rf = DJIMotorInit(&chassis_motor_steering_config);
|
motor_steering_rf = DJIMotorInit(&chassis_motor_steering_config);
|
||||||
|
|
||||||
chassis_motor_steering_config.can_init_config.tx_id = 2;
|
chassis_motor_steering_config.can_init_config.tx_id = 1;
|
||||||
motor_steering_lb = DJIMotorInit(&chassis_motor_steering_config);
|
motor_steering_lb = DJIMotorInit(&chassis_motor_steering_config);
|
||||||
|
|
||||||
PID_Init_Config_s chassis_follow_pid_conf = {
|
PID_Init_Config_s chassis_follow_pid_conf = {
|
||||||
.Kp = 1.05, // 6
|
.Kp = 1.2, // 6
|
||||||
.Ki = 0,
|
.Ki = 0,
|
||||||
.Kd = 0.1, // 0.495
|
.Kd = 0.1f, // 0.5
|
||||||
.DeadBand = 0.5f,// 启用死区,值为0.5度
|
.DeadBand = 0.5,
|
||||||
// .CoefA = 0.2,
|
// .CoefA = 0.2,
|
||||||
// .CoefB = 0.3,
|
// .CoefB = 0.3,
|
||||||
// .Improve = PID_Trapezoid_Intergral | PID_DerivativeFilter | PID_DerivativeFilter | PID_Derivative_On_Measurement | PID_Integral_Limit | PID_Derivative_On_Measurement,
|
// .Improve = PID_Trapezoid_Intergral | PID_DerivativeFilter | PID_DerivativeFilter | PID_Derivative_On_Measurement | PID_Integral_Limit | PID_Derivative_On_Measurement,
|
||||||
// .IntegralLimit = 50, // 200
|
// .IntegralLimit = 50, // 200
|
||||||
.MaxOut = 45,
|
.MaxOut = 50,
|
||||||
// .Derivative_LPF_RC = 0.01, // 0.01
|
// .Derivative_LPF_RC = 0.01, // 0.01
|
||||||
};
|
};
|
||||||
PIDInit(&chassis_follow_pid, &chassis_follow_pid_conf);
|
PIDInit(&chassis_follow_pid, &chassis_follow_pid_conf);
|
||||||
@@ -171,11 +173,14 @@ void ChassisInit()
|
|||||||
SuperCap_Init_Config_s cap_conf = {
|
SuperCap_Init_Config_s cap_conf = {
|
||||||
.can_config = {
|
.can_config = {
|
||||||
.can_handle = &hcan2,
|
.can_handle = &hcan2,
|
||||||
.tx_id = 0x302, // 超级电容默认接收id
|
.tx_id = 0x001, // 超级电容默认接收id
|
||||||
.rx_id = 0x301, // 超级电容默认发送id,注意tx和rx在其他人看来是反的
|
.rx_id = 0x100, // 超级电容默认发送id,注意tx和rx在其他人看来是反的
|
||||||
}};
|
}};
|
||||||
cap = SuperCapInit(&cap_conf); // 超级电容初始化
|
cap = SuperCapInit(&cap_conf); // 超级电容初始化
|
||||||
|
|
||||||
|
// (新增)设置超级电容功率补偿,例如补偿5W,可根据实际需求调整
|
||||||
|
SuperCapSetPowerOffset(cap, 5);
|
||||||
|
|
||||||
// 发布订阅初始化,如果为双板,则需要can comm来传递消息
|
// 发布订阅初始化,如果为双板,则需要can comm来传递消息
|
||||||
#ifdef CHASSIS_BOARD
|
#ifdef CHASSIS_BOARD
|
||||||
Chassis_IMU_data = INS_Init(); // 底盘IMU初始化
|
Chassis_IMU_data = INS_Init(); // 底盘IMU初始化
|
||||||
@@ -232,7 +237,7 @@ static void MinmizeRotation(float *angle, const float *last_angle, float *speed)
|
|||||||
while (norm_rotation < -180.0f) {
|
while (norm_rotation < -180.0f) {
|
||||||
norm_rotation += 360.0f;
|
norm_rotation += 360.0f;
|
||||||
}
|
}
|
||||||
float threshold = 110.0f;
|
float threshold = 90.0f;
|
||||||
float target_single=fmodf(target_angle,360.0f);
|
float target_single=fmodf(target_angle,360.0f);
|
||||||
if(target_single<0.0f) target_single+=360.0f;
|
if(target_single<0.0f) target_single+=360.0f;
|
||||||
|
|
||||||
@@ -249,7 +254,6 @@ static void MinmizeRotation(float *angle, const float *last_angle, float *speed)
|
|||||||
*angle = actual_angle + norm_rotation+180.0f+round_diff*360.0f;
|
*angle = actual_angle + norm_rotation+180.0f+round_diff*360.0f;
|
||||||
*speed = -(*speed);
|
*speed = -(*speed);
|
||||||
}
|
}
|
||||||
// ANGLE_LIMIT_360_TO_180_ABS(*angle);
|
|
||||||
// float rotation = *angle - *last_angle;
|
// float rotation = *angle - *last_angle;
|
||||||
// ANGLE_LIMIT_360_TO_180_ABS(rotation);
|
// ANGLE_LIMIT_360_TO_180_ABS(rotation);
|
||||||
// if (rotation > 90) {
|
// if (rotation > 90) {
|
||||||
@@ -270,55 +274,52 @@ static void MinmizeRotation(float *angle, const float *last_angle, float *speed)
|
|||||||
{
|
{
|
||||||
float offset_rf, offset_lb; // 用于计算舵轮的角度
|
float offset_rf, offset_lb; // 用于计算舵轮的角度
|
||||||
float at_rf_last, at_lb_last; // 上次的角度
|
float at_rf_last, at_lb_last; // 上次的角度
|
||||||
at_lb_last = motor_steering_lb->measure.total_angle;
|
|
||||||
// at_lf_last = motor_steering_lf->measure.total_angle;
|
|
||||||
at_rf_last = motor_steering_rf->measure.total_angle;
|
at_rf_last = motor_steering_rf->measure.total_angle;
|
||||||
// at_rb_last = motor_steering_rb->measure.total_angle;
|
at_lb_last = motor_steering_lb->measure.total_angle;
|
||||||
if (chassis_vx == 0 && chassis_vy == 0 && chassis_cmd_recv.wz == 0) {
|
if (chassis_vx == 0 && chassis_vy == 0 && chassis_cmd_recv.wz == 0) {
|
||||||
// at_lf = at_lf_last;
|
// at_lf = at_lf_last;
|
||||||
// at_rf = at_rf_last;
|
// at_rf = at_rf_last;
|
||||||
// at_lb = at_lb_last;
|
// at_lb = at_lb_last;
|
||||||
// at_rb = at_rb_last;
|
// at_rb = at_rb_last;
|
||||||
vt_lb = 0, vt_rf = 0;
|
vt_rf = 0, vt_lb = 0;
|
||||||
} else {
|
} else {
|
||||||
// 生成预计算变量,减少计算量,空间换时间
|
// 生成预计算变量,减少计算量,空间换时间
|
||||||
float w = chassis_cmd_recv.wz * CHASSIS_WHEEL_OFFSET * SQRT2;
|
//float w = chassis_cmd_recv.wz * CHASSIS_WHEEL_OFFSET * SQRT2;
|
||||||
float temp_x = chassis_vx - w, temp_y = chassis_vy - w;
|
float w = chassis_cmd_recv.wz * CHASSIS_WHEEL_OFFSET ;
|
||||||
|
// float temp_x = chassis_vx - w, temp_y = chassis_vy - w;
|
||||||
// arm_sqrt_f32(temp_x * temp_x + temp_y * temp_y, &vt_lf); // lf:y- , x-
|
// arm_sqrt_f32(temp_x * temp_x + temp_y * temp_y, &vt_lf); // lf:y- , x-
|
||||||
// temp_y = chassis_vy + w; // 重复利用变量,temp_x = chassis_vy - w;与上次相同因此注释
|
// temp_y = chassis_vy + w; // 重复利用变量,temp_x = chassis_vy - w;与上次相同因此注释
|
||||||
arm_sqrt_f32(temp_x * temp_x + temp_y * temp_y, &vt_lb); // lb: y+ , x-
|
// // arm_sqrt_f32(temp_x * temp_x + temp_y * temp_y, &vt_lb); // lb: y+ , x-
|
||||||
temp_x = chassis_vx + w;
|
// // temp_x = chassis_vx + w; // temp_y = chassis_vx + w;与上次相同因此注释
|
||||||
temp_y = chassis_vy + w;//与上次相同因此注释
|
|
||||||
// arm_sqrt_f32(temp_x * temp_x + temp_y * temp_y, &vt_rb); // rb: y+ , x+
|
// arm_sqrt_f32(temp_x * temp_x + temp_y * temp_y, &vt_rb); // rb: y+ , x+
|
||||||
// temp_y = chassis_vy - w; // temp_x = chassis_vy + w;与上次相同因此注释
|
// temp_y = chassis_vy - w; // temp_x = chassis_vy + w;与上次相同因此注释
|
||||||
|
// // arm_sqrt_f32(temp_x * temp_x + temp_y * temp_y, &vt_rf); // rf: y- , x+
|
||||||
|
float temp_x = chassis_vx - w, temp_y = chassis_vy + w;
|
||||||
|
arm_sqrt_f32(temp_x * temp_x + temp_y * temp_y, &vt_lb); // lb: y+ , x-
|
||||||
|
temp_x = chassis_vx + w;
|
||||||
|
temp_y = chassis_vy - w;
|
||||||
arm_sqrt_f32(temp_x * temp_x + temp_y * temp_y, &vt_rf); // rf: y- , x+
|
arm_sqrt_f32(temp_x * temp_x + temp_y * temp_y, &vt_rf); // rf: y- , x+
|
||||||
|
|
||||||
// 计算角度偏移
|
// 计算角度偏移
|
||||||
// offset_lf = atan2f(chassis_vy - w, chassis_vx - w) * RAD_2_DEGREE; // lf: y- , x-
|
// offset_lf = atan2f(chassis_vy - w, chassis_vx - w) * RAD_2_DEGREE; // lf: y- , x-
|
||||||
offset_rf = atan2f(chassis_vy - w, chassis_vx - w) * RAD_2_DEGREE; // rf: y- , x+
|
|
||||||
offset_lb = atan2f(chassis_vy + w, chassis_vx + w) * RAD_2_DEGREE; // lb: y+ , x-注意
|
|
||||||
// offset_rb = atan2f(chassis_vy + w, chassis_vx + w) * RAD_2_DEGREE; // rb: y+ , x+
|
// offset_rb = atan2f(chassis_vy + w, chassis_vx + w) * RAD_2_DEGREE; // rb: y+ , x+
|
||||||
|
offset_lb = atan2f(chassis_vy + w, chassis_vx - w) * RAD_2_DEGREE; // lb: y+ , x-
|
||||||
|
offset_rf = atan2f(chassis_vy - w, chassis_vx + w) * RAD_2_DEGREE; // rf: y- , x+
|
||||||
|
|
||||||
// at_lf = STEERING_CHASSIS_ALIGN_ANGLE_LF + offset_lf; // 此处似乎不需要加上真实角度,因为我们需要的是绝对角度而不是相对角度
|
at_rf = STEERING_CHASSIS_ALIGN_ANGLE_RF + offset_rf; // 此处似乎不需要加上真实角度,因为我们需要的是绝对角度而不是相对角度
|
||||||
at_rf = STEERING_CHASSIS_ALIGN_ANGLE_RF + offset_rf;
|
|
||||||
at_lb = STEERING_CHASSIS_ALIGN_ANGLE_LB + offset_lb;
|
at_lb = STEERING_CHASSIS_ALIGN_ANGLE_LB + offset_lb;
|
||||||
// at_rb = STEERING_CHASSIS_ALIGN_ANGLE_RB + offset_rb;
|
|
||||||
|
|
||||||
// ANGLE_LIMIT_360_TO_180_ABS(at_lf);
|
|
||||||
ANGLE_LIMIT_360_TO_180_ABS(at_rf);
|
ANGLE_LIMIT_360_TO_180_ABS(at_rf);
|
||||||
ANGLE_LIMIT_360_TO_180_ABS(at_lb);
|
ANGLE_LIMIT_360_TO_180_ABS(at_lb);
|
||||||
// ANGLE_LIMIT_360_TO_180_ABS(at_rb);
|
|
||||||
|
|
||||||
// MinmizeRotation(&at_lf, &at_lf_last, &vt_lf);
|
// MinmizeRotation(&at_lf, &at_lf_last, &vt_lf);
|
||||||
MinmizeRotation(&at_rf, &at_rf_last, &vt_rf);
|
|
||||||
MinmizeRotation(&at_lb, &at_lb_last, &vt_lb);
|
|
||||||
// MinmizeRotation(&at_rb, &at_rb_last, &vt_rb);
|
// MinmizeRotation(&at_rb, &at_rb_last, &vt_rb);
|
||||||
|
MinmizeRotation(&at_lb, &at_lb_last, &vt_lb);
|
||||||
|
MinmizeRotation(&at_rf, &at_rf_last, &vt_rf);
|
||||||
}
|
}
|
||||||
|
|
||||||
// DJIMotorSetRef(motor_steering_lf, at_lf);
|
|
||||||
DJIMotorSetRef(motor_steering_rf, at_rf);
|
DJIMotorSetRef(motor_steering_rf, at_rf);
|
||||||
DJIMotorSetRef(motor_steering_lb, at_lb);
|
DJIMotorSetRef(motor_steering_lb, at_lb);
|
||||||
// DJIMotorSetRef(motor_steering_rb, at_rb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -365,8 +366,7 @@ static void EstimateSpeed()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 机器人底盘控制核心任务 */
|
/* 机器人底盘控制核心任务 */
|
||||||
void ChassisTask()
|
void ChassisTask() {
|
||||||
{
|
|
||||||
// 后续增加没收到消息的处理(双板的情况)
|
// 后续增加没收到消息的处理(双板的情况)
|
||||||
// 获取新的控制信息
|
// 获取新的控制信息
|
||||||
#ifdef ONE_BOARD
|
#ifdef ONE_BOARD
|
||||||
@@ -399,7 +399,7 @@ void ChassisTask()
|
|||||||
chassis_cmd_recv.wz = 0;
|
chassis_cmd_recv.wz = 0;
|
||||||
break;
|
break;
|
||||||
case CHASSIS_FOLLOW_GIMBAL_YAW: // 跟随云台,不单独设置pid,以误差角度平方为速度输出
|
case CHASSIS_FOLLOW_GIMBAL_YAW: // 跟随云台,不单独设置pid,以误差角度平方为速度输出
|
||||||
// float single_round_offset = chassis_cmd_recv.offset_angle;
|
//chassis_cmd_recv.wz = PIDCalculate(&chassis_follow_pid, chassis_cmd_recv.offset_angle, 0);
|
||||||
float single_round_offset = chassis_cmd_recv.offset_angle;
|
float single_round_offset = chassis_cmd_recv.offset_angle;
|
||||||
if(single_round_offset > 180.0f)
|
if(single_round_offset > 180.0f)
|
||||||
{
|
{
|
||||||
@@ -409,35 +409,62 @@ void ChassisTask()
|
|||||||
{
|
{
|
||||||
single_round_offset += 360.0f;
|
single_round_offset += 360.0f;
|
||||||
}
|
}
|
||||||
chassis_cmd_recv.wz = PIDCalculate(&chassis_follow_pid, single_round_offset, 0)/100;
|
chassis_cmd_recv.wz = -PIDCalculate(&chassis_follow_pid, single_round_offset, 0)/60.0f;
|
||||||
// chassis_cmd_recv.wz = PIDCalculate(&chassis_follow_pid, chassis_cmd_recv.offset_angle, 0)/100;
|
|
||||||
break;
|
break;
|
||||||
case CHASSIS_ROTATE: // 自旋,同时保持全向机动;当前wz维持定值,后续增加不规则的变速策略
|
case CHASSIS_ROTATE: // 自旋,同时保持全向机动;当前wz维持定值,后续增加不规则的变速策略
|
||||||
chassis_cmd_recv.wz = 0.5;
|
chassis_cmd_recv.wz = 1.00;//实验版
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 根据云台和底盘的角度offset将控制量映射到底盘坐标系上
|
|
||||||
// 底盘逆时针旋转为角度正方向;云台命令的方向以云台指向的方向为x,采用右手系(x指向正北时y在正东)
|
|
||||||
static float sin_theta, cos_theta;
|
static float sin_theta, cos_theta;
|
||||||
|
// ------------------ 【修改部分:加入相位滞后动态补偿】 ------------------
|
||||||
|
// 提取当前的云台-底盘夹角
|
||||||
|
float real_offset_angle = chassis_cmd_recv.offset_angle;
|
||||||
|
|
||||||
|
// 如果处于小陀螺模式(或者 wz 不为 0),根据旋转速度进行超前补偿
|
||||||
|
if (chassis_cmd_recv.chassis_mode == CHASSIS_ROTATE )
|
||||||
|
{
|
||||||
|
// 补偿系数 K 需要实车微调。
|
||||||
|
// 根据你的描述 wz=0.95 时偏差约45度,初始 K 值可以设为 45.0 / 0.95 ≈ 47.3f
|
||||||
|
float lag_compensation_K = 47.3f;//47.3f;45.0f
|
||||||
|
|
||||||
|
// 符号(+或-)取决于你的电机正方向、底盘旋转正方向,如果不正就改成减号
|
||||||
|
real_offset_angle -= (chassis_cmd_recv.wz * lag_compensation_K);
|
||||||
|
cos_theta = arm_cos_f32(real_offset_angle * DEGREE_2_RAD);
|
||||||
|
sin_theta = arm_sin_f32(real_offset_angle * DEGREE_2_RAD);
|
||||||
|
|
||||||
|
}else if (chassis_cmd_recv.chassis_mode == CHASSIS_FOLLOW_GIMBAL_YAW)
|
||||||
|
{
|
||||||
cos_theta = arm_cos_f32(chassis_cmd_recv.offset_angle * DEGREE_2_RAD);
|
cos_theta = arm_cos_f32(chassis_cmd_recv.offset_angle * DEGREE_2_RAD);
|
||||||
sin_theta = arm_sin_f32(chassis_cmd_recv.offset_angle * DEGREE_2_RAD);
|
sin_theta = arm_sin_f32(chassis_cmd_recv.offset_angle * DEGREE_2_RAD);
|
||||||
chassis_vx = chassis_cmd_recv.vx * cos_theta - chassis_cmd_recv.vy * sin_theta;
|
|
||||||
chassis_vy = -chassis_cmd_recv.vx * sin_theta - chassis_cmd_recv.vy * cos_theta;
|
}
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
chassis_vx = (chassis_cmd_recv.vx * cos_theta + chassis_cmd_recv.vy * sin_theta)/4;
|
||||||
|
chassis_vy = (-chassis_cmd_recv.vx * sin_theta + chassis_cmd_recv.vy * cos_theta)/4;
|
||||||
|
|
||||||
|
// 使用补偿后的角度进行坐标系投影
|
||||||
|
|
||||||
|
|
||||||
|
// static float sin_theta, cos_theta;
|
||||||
|
// cos_theta = arm_cos_f32(chassis_cmd_recv.offset_angle * DEGREE_2_RAD);
|
||||||
|
// sin_theta = arm_sin_f32(chassis_cmd_recv.offset_angle * DEGREE_2_RAD);
|
||||||
|
// chassis_vx = (chassis_cmd_recv.vx * cos_theta + chassis_cmd_recv.vy * sin_theta)/4;
|
||||||
|
// chassis_vy = (-chassis_cmd_recv.vx * sin_theta + chassis_cmd_recv.vy * cos_theta)/4;
|
||||||
|
|
||||||
// 根据控制模式进行正运动学解算,计算底盘输出
|
// 根据控制模式进行正运动学解算,计算底盘输出
|
||||||
SteeringWheelCalculate();
|
SteeringWheelCalculate();
|
||||||
// MecanumCalculate();
|
// MecanumCalculate();
|
||||||
|
|
||||||
|
|
||||||
// 根据裁判系统的反馈数据和电容数据对输出限幅并设定闭环参考值
|
// 根据裁判系统的反馈数据和电容数据对输出限幅并设定闭环参考值
|
||||||
LimitChassisOutput();
|
LimitChassisOutput();
|
||||||
|
|
||||||
// 根据电机的反馈速度和IMU(如果有)计算真实速度
|
// 根据电机的反馈速度和IMU(如果有)计算真实速度
|
||||||
EstimateSpeed();
|
EstimateSpeed();
|
||||||
|
|
||||||
// // 获取裁判系统数据 建议将裁判系统与底盘分离,所以此处数据应使用消息中心发送
|
// // 获取裁判系统数据 建议将裁判系统与底盘分离,所以此处数据应使用消息中心发送/
|
||||||
// // 我方颜色id小于7是红色,大于7是蓝色,注意这里发送的是对方的颜色, 0:blue , 1:red
|
// // 我方颜色id小于7是红色,大于7是蓝色,注意这里发送的是对方的颜色, 0:blue , 1:red
|
||||||
// chassis_feedback_data.enemy_color = referee_data->GameRobotState.robot_id > 7 ? 1 : 0;
|
// chassis_feedback_data.enemy_color = referee_data->GameRobotState.robot_id > 7 ? 1 : 0;
|
||||||
// // 当前只做了17mm热量的数据获取,后续根据robot_def中的宏切换双枪管和英雄42mm的情况
|
// // 当前只做了17mm热量的数据获取,后续根据robot_def中的宏切换双枪管和英雄42mm的情况
|
||||||
|
|||||||
@@ -8,10 +8,12 @@
|
|||||||
#include "message_center.h"
|
#include "message_center.h"
|
||||||
#include "general_def.h"
|
#include "general_def.h"
|
||||||
#include "dji_motor.h"
|
#include "dji_motor.h"
|
||||||
|
#include "referee_task.h"
|
||||||
// bsp
|
// bsp
|
||||||
#include "bsp_dwt.h"
|
#include "bsp_dwt.h"
|
||||||
#include "bsp_log.h"
|
#include "bsp_log.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
#include "shoot.h"
|
||||||
// 私有宏,自动将编码器转换成角度值
|
// 私有宏,自动将编码器转换成角度值
|
||||||
#define YAW_ALIGN_ANGLE (YAW_CHASSIS_ALIGN_ECD * ECD_ANGLE_COEF_DJI) // 对齐时的角度,0-360
|
#define YAW_ALIGN_ANGLE (YAW_CHASSIS_ALIGN_ECD * ECD_ANGLE_COEF_DJI) // 对齐时的角度,0-360
|
||||||
#define PTICH_HORIZON_ANGLE (PITCH_HORIZON_ECD * ECD_ANGLE_COEF_DJI) // pitch水平时电机的角度,0-360
|
#define PTICH_HORIZON_ANGLE (PITCH_HORIZON_ECD * ECD_ANGLE_COEF_DJI) // pitch水平时电机的角度,0-360
|
||||||
@@ -44,6 +46,7 @@ static Shoot_Ctrl_Cmd_s shoot_cmd_send; // 传递给发射的控制信息
|
|||||||
static Shoot_Upload_Data_s shoot_fetch_data; // 从发射获取的反馈信息
|
static Shoot_Upload_Data_s shoot_fetch_data; // 从发射获取的反馈信息
|
||||||
|
|
||||||
static Robot_Status_e robot_state; // 机器人整体工作状态
|
static Robot_Status_e robot_state; // 机器人整体工作状态
|
||||||
|
static uint8_t robot_level = 1; // 机器人等级,范围1-10,上电重置为1
|
||||||
|
|
||||||
void RobotCMDInit()
|
void RobotCMDInit()
|
||||||
{
|
{
|
||||||
@@ -84,9 +87,17 @@ void RobotCMDInit()
|
|||||||
static void CalcOffsetAngle()
|
static void CalcOffsetAngle()
|
||||||
{
|
{
|
||||||
static float last_offset_angle = 0;
|
static float last_offset_angle = 0;
|
||||||
const float smooth_factor = 0.3f; // 平滑因子,0~1之间,值越大平滑效果越明显
|
//const float smooth_factor = 0.3f; // 平滑因子,
|
||||||
|
|
||||||
const float deadband = 3.0f; // 死区值
|
float smooth_factor;
|
||||||
|
// 小陀螺模式下使用更大的平滑因子,让offset_angle更快跟随云台
|
||||||
|
if (chassis_cmd_send.chassis_mode == CHASSIS_ROTATE) {
|
||||||
|
smooth_factor = 0.9f; // 快速响应
|
||||||
|
} else {
|
||||||
|
smooth_factor = 0.3f; // 平滑过渡 0~1之间,值越大平滑效果越明显
|
||||||
|
}
|
||||||
|
|
||||||
|
//const float deadband = 3.0f; // 死区值
|
||||||
// 新增:跟踪模式变化,用于重置基准角度
|
// 新增:跟踪模式变化,用于重置基准角度
|
||||||
// static chassis_mode_e last_chassis_mode = CHASSIS_NO_FOLLOW;//
|
// static chassis_mode_e last_chassis_mode = CHASSIS_NO_FOLLOW;//
|
||||||
//
|
//
|
||||||
@@ -108,14 +119,14 @@ static void CalcOffsetAngle()
|
|||||||
else if (angle_diff < -180.0f)
|
else if (angle_diff < -180.0f)
|
||||||
new_offset += 360.0f;
|
new_offset += 360.0f;
|
||||||
/////
|
/////
|
||||||
// 应用死区
|
// // 应用死区
|
||||||
if (fabs(new_offset) < deadband) {
|
// if (fabs(new_offset) < deadband) {
|
||||||
new_offset = 0.0f;
|
// new_offset = 0.0f;
|
||||||
} else if (new_offset > 0) {
|
// } else if (new_offset > 0) {
|
||||||
new_offset -= deadband;
|
// new_offset -= deadband;
|
||||||
} else {
|
// } else {
|
||||||
new_offset += deadband;
|
// new_offset += deadband;
|
||||||
}//////
|
// }//////
|
||||||
chassis_cmd_send.offset_angle = last_offset_angle *(1.0f - smooth_factor) + new_offset * smooth_factor;
|
chassis_cmd_send.offset_angle = last_offset_angle *(1.0f - smooth_factor) + new_offset * smooth_factor;
|
||||||
last_offset_angle = chassis_cmd_send.offset_angle;
|
last_offset_angle = chassis_cmd_send.offset_angle;
|
||||||
// // 更新模式状态
|
// // 更新模式状态
|
||||||
@@ -184,12 +195,12 @@ static void RemoteControlSet()
|
|||||||
// around = 0;
|
// around = 0;
|
||||||
chassis_cmd_send.chassis_mode = CHASSIS_ROTATE;
|
chassis_cmd_send.chassis_mode = CHASSIS_ROTATE;
|
||||||
gimbal_cmd_send.gimbal_mode = GIMBAL_GYRO_MODE;
|
gimbal_cmd_send.gimbal_mode = GIMBAL_GYRO_MODE;
|
||||||
around= chassis_cmd_send.offset_angle/360;
|
around= chassis_cmd_send.offset_angle/(-360);
|
||||||
}
|
}
|
||||||
else if (switch_is_mid(rc_data[TEMP].rc.switch_right)) // 右侧开关状态[中],底盘和云台分离,底盘保持不转动
|
else if (switch_is_mid(rc_data[TEMP].rc.switch_right)) // 右侧开关状态[中],底盘和云台分离,底盘保持不转动
|
||||||
{
|
{
|
||||||
//gimbal_fetch_data.yaw_motor_total_angle = gimbal_fetch_data.yaw_motor_total_angle-around*360;
|
//gimbal_fetch_data.yaw_motor_total_angle = gimbal_fetch.yaw_motor_total_angle-around*360;
|
||||||
chassis_cmd_send.offset_angle = chassis_cmd_send.offset_angle - 360*around;
|
chassis_cmd_send.offset_angle = chassis_cmd_send.offset_angle + 360*around;
|
||||||
chassis_cmd_send.chassis_mode = CHASSIS_FOLLOW_GIMBAL_YAW;
|
chassis_cmd_send.chassis_mode = CHASSIS_FOLLOW_GIMBAL_YAW;
|
||||||
gimbal_cmd_send.gimbal_mode = GIMBAL_GYRO_MODE;
|
gimbal_cmd_send.gimbal_mode = GIMBAL_GYRO_MODE;
|
||||||
}
|
}
|
||||||
@@ -197,7 +208,7 @@ static void RemoteControlSet()
|
|||||||
// 云台参数,确定云台控制数据
|
// 云台参数,确定云台控制数据
|
||||||
if (switch_is_mid(rc_data[TEMP].rc.switch_left)) // 左侧开关状态为[中],视觉模式
|
if (switch_is_mid(rc_data[TEMP].rc.switch_left)) // 左侧开关状态为[中],视觉模式
|
||||||
{
|
{
|
||||||
// 待添加,视觉会发来和目标的误差,同样将其转化为total angle的增量进行控制
|
// 待添加,视觉会发来和目标的误差,同样将其转化为total angle的增量进行控制/
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
// 左侧开关状态为[下],或视觉未识别到目标,纯遥控器拨杆控制
|
// 左侧开关状态为[下],或视觉未识别到目标,纯遥控器拨杆控制
|
||||||
@@ -207,11 +218,15 @@ static void RemoteControlSet()
|
|||||||
gimbal_cmd_send.pitch += 0.001f * (float)rc_data[TEMP].rc.rocker_l1;
|
gimbal_cmd_send.pitch += 0.001f * (float)rc_data[TEMP].rc.rocker_l1;
|
||||||
}
|
}
|
||||||
// 云台软件限位
|
// 云台软件限位
|
||||||
|
if (gimbal_cmd_send.pitch > PITCH_MAX_ANGLE)
|
||||||
|
gimbal_cmd_send.pitch = PITCH_MAX_ANGLE;
|
||||||
|
else if (gimbal_cmd_send.pitch < PITCH_MIN_ANGLE)
|
||||||
|
gimbal_cmd_send.pitch = PITCH_MIN_ANGLE;
|
||||||
|
|
||||||
// 底盘参数,目前没有加入小陀螺(调试似乎暂时没有必要),系数需要调整
|
// 底盘参数,目前没有加入小陀螺(调试似乎暂时没有必要),系数需要调整
|
||||||
chassis_cmd_send.vx = 0.15f * (float)rc_data[TEMP].rc.rocker_r_; // _水平方向
|
chassis_cmd_send.vx = (0.25f * (float)rc_data[TEMP].rc.rocker_r1); // 竖直方向
|
||||||
chassis_cmd_send.vy = 0.15f * (float)rc_data[TEMP].rc.rocker_r1; // 1数值方向
|
chassis_cmd_send.vy = (0.25f * (float)rc_data[TEMP].rc.rocker_r_); // 水平方向
|
||||||
|
//此处如果是右手系,那么x应该是前进方向即竖直方向
|
||||||
// // 发射参数
|
// // 发射参数
|
||||||
// if (switch_is_up(rc_data[TEMP].rc.switch_right)) // 右侧开关状态[上],弹舱打开
|
// if (switch_is_up(rc_data[TEMP].rc.switch_right)) // 右侧开关状态[上],弹舱打开
|
||||||
// ; // 弹舱舵机控制,待添加servo_motor模块,开启
|
// ; // 弹舱舵机控制,待添加servo_motor模块,开启
|
||||||
@@ -224,8 +239,8 @@ static void RemoteControlSet()
|
|||||||
else
|
else
|
||||||
shoot_cmd_send.friction_mode = FRICTION_OFF;
|
shoot_cmd_send.friction_mode = FRICTION_OFF;
|
||||||
// 拨弹控制,遥控器固定为一种拨弹模式,可自行选择
|
// 拨弹控制,遥控器固定为一种拨弹模式,可自行选择
|
||||||
if (rc_data[TEMP].rc.dial < -500)
|
if (rc_data[TEMP].rc.dial >500)
|
||||||
shoot_cmd_send.load_mode = LOAD_BURSTFIRE;
|
shoot_cmd_send.load_mode = LOAD_3_BULLET;
|
||||||
else
|
else
|
||||||
shoot_cmd_send.load_mode = LOAD_STOP;
|
shoot_cmd_send.load_mode = LOAD_STOP;
|
||||||
// 射频控制,固定每秒1发,后续可以根据左侧拨轮的值大小切换射频,
|
// 射频控制,固定每秒1发,后续可以根据左侧拨轮的值大小切换射频,
|
||||||
@@ -238,13 +253,74 @@ static void RemoteControlSet()
|
|||||||
*/
|
*/
|
||||||
static void MouseKeySet()
|
static void MouseKeySet()
|
||||||
{
|
{
|
||||||
chassis_cmd_send.vx = rc_data[TEMP].key[KEY_PRESS].w * 300 - rc_data[TEMP].key[KEY_PRESS].s * 300; // 系数待测
|
|
||||||
chassis_cmd_send.vy = rc_data[TEMP].key[KEY_PRESS].s * 300 - rc_data[TEMP].key[KEY_PRESS].d * 300;
|
// // G键控制机器人等级,每次按G键等级+1,最高10级/
|
||||||
|
// if (rc_data[TEMP].key[KEY_PRESS].g && rc_data[TEMP].key_count[KEY_PRESS][Key_G] > 0) {
|
||||||
|
// robot_level = (robot_level % 10) + 1; // 等级循环增加,1-10
|
||||||
|
// }
|
||||||
|
// G键控制机器人等级,每次按G键等级+1,最高10级
|
||||||
|
if (rc_data[TEMP].key[KEY_PRESS].g && rc_data[TEMP].key_count[KEY_PRESS][Key_G] > 0) {
|
||||||
|
robot_level = (robot_level % 10) + 1; // 等级循环增加,1-10
|
||||||
|
rc_data[TEMP].key_count[KEY_PRESS][Key_G] = 0; // 清除计数器,防止重复执行
|
||||||
|
}
|
||||||
|
|
||||||
|
// B键刷新裁判系统UI
|
||||||
|
if (rc_data[TEMP].key[KEY_PRESS].b && rc_data[TEMP].key_count[KEY_PRESS][Key_B] > 0) {
|
||||||
|
MyUIInit(); // 重新初始化UI
|
||||||
|
rc_data[TEMP].key_count[KEY_PRESS][Key_B] = 0; // 清除计数器,防止重复执行
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将robot_level传递给底盘控制命令
|
||||||
|
chassis_cmd_send.robot_level = robot_level;
|
||||||
|
chassis_cmd_send.vx = rc_data[TEMP].key[KEY_PRESS].a * 42 - rc_data[TEMP].key[KEY_PRESS].d * 42; // w向前,s向后
|
||||||
|
chassis_cmd_send.vy = rc_data[TEMP].key[KEY_PRESS].w * 42 - rc_data[TEMP].key[KEY_PRESS].s * 42; // a向左,d向右
|
||||||
|
// switch (robot_level)
|
||||||
|
// {
|
||||||
|
// case 1:
|
||||||
|
// case 2:
|
||||||
|
// case 3:
|
||||||
|
// chassis_cmd_send.vx = (rc_data[TEMP].key[KEY_PRESS].a * 20 - rc_data[TEMP].key[KEY_PRESS].d * 20); // w向前,s向后
|
||||||
|
// chassis_cmd_send.vy = (rc_data[TEMP].key[KEY_PRESS].w * 20 - rc_data[TEMP].key[KEY_PRESS].s * 20); // a向左,d向右
|
||||||
|
// break;
|
||||||
|
// case 4:
|
||||||
|
// case 5:
|
||||||
|
// case 6:
|
||||||
|
// case 7:
|
||||||
|
// chassis_cmd_send.vx = (rc_data[TEMP].key[KEY_PRESS].a * 30 - rc_data[TEMP].key[KEY_PRESS].d * 30); // w向前,s向后
|
||||||
|
// chassis_cmd_send.vy = (rc_data[TEMP].key[KEY_PRESS].w * 30 - rc_data[TEMP].key[KEY_PRESS].s * 30); // a向左,d向右
|
||||||
|
// break;
|
||||||
|
// default:
|
||||||
|
// chassis_cmd_send.vx = (rc_data[TEMP].key[KEY_PRESS].a * 40 - rc_data[TEMP].key[KEY_PRESS].d * 40); // w向前,s向后
|
||||||
|
// chassis_cmd_send.vy = (rc_data[TEMP].key[KEY_PRESS].w * 40 - rc_data[TEMP].key[KEY_PRESS].s * 40); // a向左,d向右
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// 根据等级设置底盘速度
|
||||||
|
// if (robot_level >= 1 && robot_level <= 3) {
|
||||||
|
// chassis_cmd_send.vx = (rc_data[TEMP].key[KEY_PRESS].a * 20 - rc_data[TEMP].key[KEY_PRESS].d * 20); // w向前,s向后
|
||||||
|
// chassis_cmd_send.vy = (rc_data[TEMP].key[KEY_PRESS].w * 20 - rc_data[TEMP].key[KEY_PRESS].s * 20); // a向左,d向右
|
||||||
|
// } else if (robot_level >= 4 && robot_level <= 7) {
|
||||||
|
// chassis_cmd_send.vx = (rc_data[TEMP].key[KEY_PRESS].a * 30 - rc_data[TEMP].key[KEY_PRESS].d * 30); // w向前,s向后
|
||||||
|
// chassis_cmd_send.vy = (rc_data[TEMP].key[KEY_PRESS].w * 30 - rc_data[TEMP].key[KEY_PRESS].s * 30); // a向左,d向右
|
||||||
|
// } else {
|
||||||
|
// chassis_cmd_send.vx = (rc_data[TEMP].key[KEY_PRESS].a * 40 - rc_data[TEMP].key[KEY_PRESS].d * 40); // w向前,s向后
|
||||||
|
// chassis_cmd_send.vy = (rc_data[TEMP].key[KEY_PRESS].w * 40 - rc_data[TEMP].key[KEY_PRESS].s * 40); // a向左,d向右
|
||||||
|
// }
|
||||||
|
|
||||||
|
// chassis_cmd_send.vx = rc_data[TEMP].key[KEY_PRESS].w * 300 - rc_data[TEMP].key[KEY_PRESS].s * 300; // 系数待测
|
||||||
|
// chassis_cmd_send.vy = rc_data[TEMP].key[KEY_PRESS].s * 300 - rc_data[TEMP].key[KEY_PRESS].d * 300;
|
||||||
|
//chassis_cmd_send.vx = (rc_data[TEMP].key[KEY_PRESS].a * 27 - rc_data[TEMP].key[KEY_PRESS].d * 27); // w向前,s向后
|
||||||
|
//chassis_cmd_send.vy = (rc_data[TEMP].key[KEY_PRESS].w * 27 - rc_data[TEMP].key[KEY_PRESS].s * 27); // a向左,d向右
|
||||||
|
|
||||||
gimbal_cmd_send.yaw += (float)rc_data[TEMP].mouse.x / 660 * 10; // 系数待测
|
gimbal_cmd_send.yaw += (float)rc_data[TEMP].mouse.x / 660 * 10; // 系数待测
|
||||||
gimbal_cmd_send.pitch += (float)rc_data[TEMP].mouse.y / 660 * 10;
|
gimbal_cmd_send.pitch += (float)rc_data[TEMP].mouse.y / 660 * 8;
|
||||||
|
|
||||||
switch (rc_data[TEMP].key_count[KEY_PRESS][Key_Z] % 3) // Z键设置弹速
|
// 云台软件限位1
|
||||||
|
if (gimbal_cmd_send.pitch > PITCH_MAX_ANGLE)
|
||||||
|
gimbal_cmd_send.pitch = PITCH_MAX_ANGLE;
|
||||||
|
else if (gimbal_cmd_send.pitch < PITCH_MIN_ANGLE)
|
||||||
|
gimbal_cmd_send.pitch = PITCH_MIN_ANGLE;
|
||||||
|
|
||||||
|
switch (rc_data[TEMP].key_count[KEY_PRESS][Key_Z] % 3) // Z键设置弹速/1
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
shoot_cmd_send.bullet_speed = 15;
|
shoot_cmd_send.bullet_speed = 15;
|
||||||
@@ -256,20 +332,45 @@ static void MouseKeySet()
|
|||||||
shoot_cmd_send.bullet_speed = 30;
|
shoot_cmd_send.bullet_speed = 30;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
switch (rc_data[TEMP].key_count[KEY_PRESS][Key_E] % 4) // E键设置发射模式
|
// switch (rc_data[TEMP].key_count[KEY_PRESS][Key_E] % 4) // E键设置发射模式
|
||||||
{
|
// {
|
||||||
case 0:
|
// case 0:
|
||||||
shoot_cmd_send.load_mode = LOAD_STOP;
|
// shoot_cmd_send.load_mode = LOAD_STOP;
|
||||||
break;
|
// break;
|
||||||
case 1:
|
// case 1:
|
||||||
shoot_cmd_send.load_mode = LOAD_1_BULLET;
|
// shoot_cmd_send.load_mode = LOAD_1_BULLET;
|
||||||
break;
|
// break;
|
||||||
case 2:
|
// case 2:
|
||||||
shoot_cmd_send.load_mode = LOAD_3_BULLET;
|
// shoot_cmd_send.load_mode = LOAD_3_BULLET;
|
||||||
break;
|
// break;
|
||||||
default:
|
// default:
|
||||||
shoot_cmd_send.load_mode = LOAD_BURSTFIRE;
|
// shoot_cmd_send.load_mode = LOAD_BURSTFIRE;
|
||||||
break;
|
// break;
|
||||||
|
// }
|
||||||
|
// switch (rc_data[TEMP].mouse.press_l) // 鼠标左键射击
|
||||||
|
// {
|
||||||
|
// case 0:
|
||||||
|
// shoot_cmd_send.load_mode = LOAD_STOP;
|
||||||
|
// break;
|
||||||
|
// default:
|
||||||
|
// shoot_cmd_send.load_mode = LOAD_1_BULLET; // 按鼠标进行单发
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// switch (rc_data[TEMP].mouse.press_r) // 鼠标右键射击
|
||||||
|
// {
|
||||||
|
// case 0:
|
||||||
|
// shoot_cmd_send.load_mode = LOAD_STOP;
|
||||||
|
// break;
|
||||||
|
// default:
|
||||||
|
// shoot_cmd_send.load_mode = LOAD_3_BULLET; // 按鼠标进行单发
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
if (rc_data[TEMP].mouse.press_l) {
|
||||||
|
shoot_cmd_send.load_mode = LOAD_BURSTFIRE; // 左键单发
|
||||||
|
} else if (rc_data[TEMP].mouse.press_r) {
|
||||||
|
shoot_cmd_send.load_mode = LOAD_3_BULLET; // 右键三连发
|
||||||
|
} else {
|
||||||
|
shoot_cmd_send.load_mode = LOAD_STOP; // 不按鼠标不发射
|
||||||
}
|
}
|
||||||
switch (rc_data[TEMP].key_count[KEY_PRESS][Key_R] % 2) // R键开关弹舱
|
switch (rc_data[TEMP].key_count[KEY_PRESS][Key_R] % 2) // R键开关弹舱
|
||||||
{
|
{
|
||||||
@@ -304,7 +405,18 @@ static void MouseKeySet()
|
|||||||
chassis_cmd_send.chassis_speed_buff = 100;
|
chassis_cmd_send.chassis_speed_buff = 100;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
switch (rc_data[TEMP].key[KEY_PRESS].shift) // 待添加 按shift允许超功率 消耗缓冲能量
|
switch (rc_data[TEMP].key_count[KEY_PRESS][Key_Q] % 2) // Q键设置底盘运动模式
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
chassis_cmd_send.offset_angle = chassis_cmd_send.offset_angle - 360*around;
|
||||||
|
chassis_cmd_send.chassis_mode = CHASSIS_FOLLOW_GIMBAL_YAW;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
chassis_cmd_send.chassis_mode = CHASSIS_ROTATE;
|
||||||
|
around= chassis_cmd_send.offset_angle/360;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (rc_data[TEMP].key[KEY_PRESS].shift) // 待添加 按shift允许超功率 消耗缓冲能量。
|
||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
|
|
||||||
@@ -317,6 +429,9 @@ static void MouseKeySet()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
* @brief 紧急停止,包括遥控器左上侧拨轮打满/重要模块离线/双板通信失效等
|
* @brief 紧急停止,包括遥控器左上侧拨轮打满/重要模块离线/双板通信失效等
|
||||||
* 停止的阈值'300'待修改成合适的值,或改为开关控制.
|
* 停止的阈值'300'待修改成合适的值,或改为开关控制.
|
||||||
*
|
*
|
||||||
@@ -330,6 +445,8 @@ static void EmergencyHandler()
|
|||||||
{
|
{
|
||||||
robot_state = ROBOT_STOP;
|
robot_state = ROBOT_STOP;
|
||||||
gimbal_cmd_send.gimbal_mode = GIMBAL_ZERO_FORCE;
|
gimbal_cmd_send.gimbal_mode = GIMBAL_ZERO_FORCE;
|
||||||
|
gimbal_cmd_send.yaw = -gimbal_fetch_data.gimbal_imu_data.YawTotalAngle;;//0
|
||||||
|
gimbal_cmd_send.pitch = 0;
|
||||||
chassis_cmd_send.chassis_mode = CHASSIS_ZERO_FORCE;
|
chassis_cmd_send.chassis_mode = CHASSIS_ZERO_FORCE;
|
||||||
shoot_cmd_send.shoot_mode = SHOOT_OFF;
|
shoot_cmd_send.shoot_mode = SHOOT_OFF;
|
||||||
shoot_cmd_send.friction_mode = FRICTION_OFF;
|
shoot_cmd_send.friction_mode = FRICTION_OFF;
|
||||||
@@ -346,8 +463,7 @@ static void EmergencyHandler()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 机器人核心控制任务,200Hz频率运行(必须高于视觉发送频率) */
|
/* 机器人核心控制任务,200Hz频率运行(必须高于视觉发送频率) */
|
||||||
void RobotCMDTask()
|
void RobotCMDTask() {
|
||||||
{
|
|
||||||
// 从其他应用获取回传数据
|
// 从其他应用获取回传数据
|
||||||
#ifdef ONE_BOARD
|
#ifdef ONE_BOARD
|
||||||
SubGetMessage(chassis_feed_sub, (void *)&chassis_fetch_data);
|
SubGetMessage(chassis_feed_sub, (void *)&chassis_fetch_data);
|
||||||
@@ -361,11 +477,25 @@ void RobotCMDTask()
|
|||||||
// 根据gimbal的反馈值计算云台和底盘正方向的夹角,不需要传参,通过static私有变量完成
|
// 根据gimbal的反馈值计算云台和底盘正方向的夹角,不需要传参,通过static私有变量完成
|
||||||
CalcOffsetAngle();
|
CalcOffsetAngle();
|
||||||
// 根据遥控器左侧开关,确定当前使用的控制模式为遥控器调试还是键鼠
|
// 根据遥控器左侧开关,确定当前使用的控制模式为遥控器调试还是键鼠
|
||||||
if (switch_is_down(rc_data[TEMP].rc.switch_left)) // 遥控器左侧开关状态为[下],遥控器控制
|
if (switch_is_down(rc_data[TEMP].rc.switch_left)){ // 遥控器左侧开关状态为[下],遥控器控制
|
||||||
RemoteControlSet();
|
RemoteControlSet();
|
||||||
else if (switch_is_up(rc_data[TEMP].rc.switch_left)) // 遥控器左侧开关状态为[上],键盘控制
|
shoot_cmd_send.shoot_mode =SHOOT_ON;
|
||||||
|
shoot_cmd_send.friction_mode = FRICTION_OFF;
|
||||||
|
}
|
||||||
|
else if (switch_is_up(rc_data[TEMP].rc.switch_left)) {
|
||||||
|
// 遥控器左侧开关状态为[上],键盘控制
|
||||||
MouseKeySet();
|
MouseKeySet();
|
||||||
|
shoot_cmd_send.shoot_mode =SHOOT_ON;
|
||||||
|
}
|
||||||
|
else if (switch_is_mid(rc_data[TEMP].rc.switch_left)) {
|
||||||
|
// 遥控器左侧开关状态为[中],视觉模式,使用遥控器控制底盘和云台,同时开启发射系统
|
||||||
|
RemoteControlSet();
|
||||||
|
gimbal_cmd_send.yaw += 0.005f * (float)rc_data[TEMP].rc.rocker_l_;
|
||||||
|
gimbal_cmd_send.pitch += 0.001f * (float)rc_data[TEMP].rc.rocker_l1;
|
||||||
|
shoot_cmd_send.shoot_mode =SHOOT_ON;
|
||||||
|
shoot_cmd_send.bullet_speed = 30;
|
||||||
|
shoot_cmd_send.friction_mode = FRICTION_ON;
|
||||||
|
}
|
||||||
EmergencyHandler(); // 处理模块离线和遥控器急停等紧急情况
|
EmergencyHandler(); // 处理模块离线和遥控器急停等紧急情况
|
||||||
|
|
||||||
// 设置视觉发送数据,还需增加加速度和角速度数据
|
// 设置视觉发送数据,还需增加加速度和角速度数据
|
||||||
|
|||||||
@@ -14,7 +14,9 @@ static Publisher_t *gimbal_pub; // 云台应用消息发布者
|
|||||||
static Subscriber_t *gimbal_sub; // cmd控制消息订阅者
|
static Subscriber_t *gimbal_sub; // cmd控制消息订阅者
|
||||||
static Gimbal_Upload_Data_s gimbal_feedback_data; // 回传给cmd的云台状态信息
|
static Gimbal_Upload_Data_s gimbal_feedback_data; // 回传给cmd的云台状态信息
|
||||||
static Gimbal_Ctrl_Cmd_s gimbal_cmd_recv; // 来自cmd的控制信息
|
static Gimbal_Ctrl_Cmd_s gimbal_cmd_recv; // 来自cmd的控制信息
|
||||||
|
static float last_yaw_angle = 0.0f; // 保护模式前的yaw角度
|
||||||
|
// static float last_pitch_angle = 0.0f; // 保护模式前的pitch角度
|
||||||
|
uint8_t in_protection_mode = 0; // 是否在保护模式
|
||||||
void GimbalInit()
|
void GimbalInit()
|
||||||
{
|
{
|
||||||
gimba_IMU_data = INS_Init(); // IMU先初始化,获取姿态数据指针赋给yaw电机的其他数据来源
|
gimba_IMU_data = INS_Init(); // IMU先初始化,获取姿态数据指针赋给yaw电机的其他数据来源
|
||||||
@@ -27,11 +29,11 @@ void GimbalInit()
|
|||||||
.controller_param_init_config = {
|
.controller_param_init_config = {
|
||||||
.angle_PID = {
|
.angle_PID = {
|
||||||
//.Kp = 0.685, // 8
|
//.Kp = 0.685, // 8
|
||||||
.Kp = 0.685, // 8
|
.Kp = 0.585, // 8
|
||||||
//.Ki = 0.315,
|
//.Ki = 0.315,
|
||||||
.Ki = 0.25,
|
.Ki = 0.25,
|
||||||
.Kd = 0.022,
|
.Kd = 0.03,
|
||||||
//.DeadBand = 0.1,
|
//.DeadBand = 0.1
|
||||||
.Improve = PID_Trapezoid_Intergral | PID_Integral_Limit | PID_Derivative_On_Measurement | PID_DerivativeFilter | PID_ChangingIntegrationRate,
|
.Improve = PID_Trapezoid_Intergral | PID_Integral_Limit | PID_Derivative_On_Measurement | PID_DerivativeFilter | PID_ChangingIntegrationRate,
|
||||||
.IntegralLimit = 1060,
|
.IntegralLimit = 1060,
|
||||||
.CoefA = 20,
|
.CoefA = 20,
|
||||||
@@ -66,24 +68,45 @@ void GimbalInit()
|
|||||||
Motor_Init_Config_s pitch_config = {
|
Motor_Init_Config_s pitch_config = {
|
||||||
.can_init_config = {
|
.can_init_config = {
|
||||||
.can_handle = &hcan2,
|
.can_handle = &hcan2,
|
||||||
.tx_id = 4,
|
.tx_id = 2,//2
|
||||||
},
|
},
|
||||||
|
// .controller_param_init_config = {
|
||||||
|
// .angle_PID = {
|
||||||
|
// .Kp = 40, // 10
|
||||||
|
// .Ki = 0,
|
||||||
|
// .Kd = 0,
|
||||||
|
// .MaxOut = 1000,
|
||||||
|
// },
|
||||||
|
// .speed_PID = {
|
||||||
|
// .Kp = 60, // 50
|
||||||
|
// .Ki = 15, // 350
|
||||||
|
// .Kd = 0.6, // 0
|
||||||
|
// .MaxOut = 20000,//20000
|
||||||
|
// },
|
||||||
.controller_param_init_config = {
|
.controller_param_init_config = {
|
||||||
.angle_PID = {
|
.angle_PID = {
|
||||||
.Kp = 10, // 10
|
.Kp = 0.53, //0.55
|
||||||
.Ki = 0,
|
.Ki = 0.1,//0.05
|
||||||
.Kd = 0,
|
.Kd = 0.0148,//0.02
|
||||||
.Improve = PID_Trapezoid_Intergral | PID_Integral_Limit | PID_Derivative_On_Measurement,
|
.CoefA =0.5,//0.5
|
||||||
.IntegralLimit = 100,
|
.CoefB = 0.6,//0.6
|
||||||
.MaxOut = 500,
|
.Output_LPF_RC = 0.0068,
|
||||||
|
.DeadBand = 0.005,//0.02
|
||||||
|
.Derivative_LPF_RC=0.01,//0.008
|
||||||
|
.Improve = PID_Trapezoid_Intergral |PID_ChangingIntegrationRate| PID_Integral_Limit |PID_Derivative_On_Measurement | PID_OutputFilter |PID_DerivativeFilter,
|
||||||
|
.IntegralLimit = 1,
|
||||||
|
.MaxOut = 600,
|
||||||
},
|
},
|
||||||
.speed_PID = {
|
.speed_PID = {
|
||||||
.Kp = 50, // 50
|
.Kp = 3400,//22000
|
||||||
.Ki = 350, // 350
|
.Ki = 15,//
|
||||||
.Kd = 0, // 0
|
.Kd =1,
|
||||||
.Improve = PID_Trapezoid_Intergral | PID_Integral_Limit | PID_Derivative_On_Measurement,
|
.CoefA = 0.8,
|
||||||
.IntegralLimit = 2500,
|
.CoefB = 0.1,
|
||||||
.MaxOut = 20000,
|
.Output_LPF_RC = 0.002,//0.002
|
||||||
|
.Improve = PID_Trapezoid_Intergral |PID_Integral_Limit |PID_Derivative_On_Measurement | PID_OutputFilter,
|
||||||
|
.IntegralLimit = 6000,
|
||||||
|
.MaxOut = 30000,
|
||||||
},
|
},
|
||||||
.other_angle_feedback_ptr = &gimba_IMU_data->Pitch,
|
.other_angle_feedback_ptr = &gimba_IMU_data->Pitch,
|
||||||
// 还需要增加角速度额外反馈指针,注意方向,ins_task.md中有c板的bodyframe坐标系说明
|
// 还需要增加角速度额外反馈指针,注意方向,ins_task.md中有c板的bodyframe坐标系说明
|
||||||
@@ -94,9 +117,12 @@ void GimbalInit()
|
|||||||
.speed_feedback_source = OTHER_FEED,
|
.speed_feedback_source = OTHER_FEED,
|
||||||
.outer_loop_type = ANGLE_LOOP,
|
.outer_loop_type = ANGLE_LOOP,
|
||||||
.close_loop_type = SPEED_LOOP | ANGLE_LOOP,
|
.close_loop_type = SPEED_LOOP | ANGLE_LOOP,
|
||||||
|
// .outer_loop_type = SPEED_LOOP,//调试用
|
||||||
|
// .close_loop_type = SPEED_LOOP,
|
||||||
.motor_reverse_flag = MOTOR_DIRECTION_NORMAL,
|
.motor_reverse_flag = MOTOR_DIRECTION_NORMAL,
|
||||||
},
|
},
|
||||||
.motor_type = M3508,
|
|
||||||
|
.motor_type = GM6020,
|
||||||
};
|
};
|
||||||
// 电机对total_angle闭环,上电时为零,会保持静止,收到遥控器数据再动
|
// 电机对total_angle闭环,上电时为零,会保持静止,收到遥控器数据再动
|
||||||
yaw_motor = DJIMotorInit(&yaw_config);
|
yaw_motor = DJIMotorInit(&yaw_config);
|
||||||
@@ -119,11 +145,25 @@ void GimbalTask()
|
|||||||
{
|
{
|
||||||
// 停止
|
// 停止
|
||||||
case GIMBAL_ZERO_FORCE:
|
case GIMBAL_ZERO_FORCE:
|
||||||
|
// 进入保护模式时记录当前角度
|
||||||
|
if (!in_protection_mode) {
|
||||||
|
last_yaw_angle = gimba_IMU_data->YawTotalAngle;
|
||||||
|
// last_pitch_angle = gimba_IMU_data->Pitch;
|
||||||
|
in_protection_mode = 1;
|
||||||
|
}
|
||||||
DJIMotorStop(yaw_motor);
|
DJIMotorStop(yaw_motor);
|
||||||
DJIMotorStop(pitch_motor);
|
DJIMotorStop(pitch_motor);
|
||||||
break;
|
break;
|
||||||
// 使用陀螺仪的反馈,底盘根据yaw电机的offset跟随云台或视觉模式采用
|
// 使用陀螺仪的反馈,底盘根据yaw电机的offset跟随云台或视觉模式采用
|
||||||
case GIMBAL_GYRO_MODE: // 后续只保留此模式
|
case GIMBAL_GYRO_MODE: // 后续只保留此模式
|
||||||
|
// 从保护模式退出时
|
||||||
|
if (in_protection_mode) {
|
||||||
|
// 计算零飘导致的角度误差
|
||||||
|
float angle_error = gimba_IMU_data->YawTotalAngle - last_yaw_angle;
|
||||||
|
// 补偿目标角度,避免突然旋转
|
||||||
|
gimbal_cmd_recv.yaw -= angle_error;
|
||||||
|
in_protection_mode = 0;
|
||||||
|
}
|
||||||
DJIMotorEnable(yaw_motor);
|
DJIMotorEnable(yaw_motor);
|
||||||
DJIMotorEnable(pitch_motor);
|
DJIMotorEnable(pitch_motor);
|
||||||
DJIMotorChangeFeed(yaw_motor, ANGLE_LOOP, OTHER_FEED);
|
DJIMotorChangeFeed(yaw_motor, ANGLE_LOOP, OTHER_FEED);
|
||||||
|
|||||||
@@ -26,24 +26,24 @@
|
|||||||
|
|
||||||
/* 机器人重要参数定义,注意根据不同机器人进行修改,浮点数需要以.0或f结尾,无符号以u结尾 */
|
/* 机器人重要参数定义,注意根据不同机器人进行修改,浮点数需要以.0或f结尾,无符号以u结尾 */
|
||||||
// 云台参数
|
// 云台参数
|
||||||
#define YAW_CHASSIS_ALIGN_ECD 3938 // 云台和底盘对齐指向相同方向时的电机编码器值,若对云台有机械改动需要修改
|
#define YAW_CHASSIS_ALIGN_ECD -3595 // 云台和底盘对齐指向相同方向时的电机编码器值,若对云台有机械改动需要修改
|
||||||
#define YAW_ECD_GREATER_THAN_4096 0 // ALIGN_ECD值是否大于4096,是为1,否为0;用于计算云台偏转角度
|
#define YAW_ECD_GREATER_THAN_4096 0 // ALIGN_ECD值是否大于4096,是为1,否为0;用于计算云台偏转角度
|
||||||
#define PITCH_HORIZON_ECD 3412 // 云台处于水平位置时编码器值,若对云台有机械改动需要修改
|
#define PITCH_HORIZON_ECD 3412 // 云台处于水平位置时编码器值,若对云台有机械改动需要修改
|
||||||
#define PITCH_MAX_ANGLE 0 // 云台竖直方向最大角度 (注意反馈如果是陀螺仪,则填写陀螺仪的角度)
|
#define PITCH_MAX_ANGLE 30 // 云台竖直方向最大角度 (注意反馈如果是陀螺仪,则填写陀螺仪的角度)
|
||||||
#define PITCH_MIN_ANGLE 0 // 云台竖直方向最小角度 (注意反馈如果是陀螺仪,则填写陀螺仪的角度)
|
#define PITCH_MIN_ANGLE -20 // 云台竖直方向最小角度 (注意反馈如果是陀螺仪,则填写陀螺仪的角度)
|
||||||
// 底盘参数
|
// 底盘参数
|
||||||
// #define CHASSIS_OMNI_WHEEL // 是否为全向轮底盘
|
// #define CHASSIS_OMNI_WHEEL // 是否为全向轮底盘
|
||||||
// #define CHASSIS_MCNAMEE_WHEEL // 是否为麦克纳姆轮底盘
|
// #define CHASSIS_MCNAMEE_WHEEL // 是否为麦克纳姆轮底盘
|
||||||
#define CHASSIS_STEERING_WHEEL // 是否为舵轮
|
#define CHASSIS_STEERING_WHEEL // 是否为舵轮
|
||||||
#define STEERING_CHASSIS_ALIGN_ECD_RF 7367 // 舵电机 A 编码器值,若有机械改动需要修改
|
#define STEERING_CHASSIS_ALIGN_ECD_RF 7066 // 舵电机 A 编码器值,若有机械改动需要修改
|
||||||
#define STEERING_CHASSIS_ALIGN_ECD_LB 1195 // 舵电机 D 编码器值,若有机械改动需要修改
|
#define STEERING_CHASSIS_ALIGN_ECD_LB 7138 // 舵电机 D 编码器值,若有机械改动需要修改
|
||||||
|
|
||||||
#define STEERING_CHASSIS_ALIGN_ANGLE_RF STEERING_CHASSIS_ALIGN_ECD_RF / 8192.f * 360.f // 舵轮 A 对齐角度
|
#define STEERING_CHASSIS_ALIGN_ANGLE_RF STEERING_CHASSIS_ALIGN_ECD_RF / 8192.f * 360.f // 舵轮 A 对齐角度
|
||||||
#define STEERING_CHASSIS_ALIGN_ANGLE_LB STEERING_CHASSIS_ALIGN_ECD_LB / 8192.f * 360.f // 舵轮 D 对齐角度
|
#define STEERING_CHASSIS_ALIGN_ANGLE_LB STEERING_CHASSIS_ALIGN_ECD_LB / 8192.f * 360.f // 舵轮 D 对齐角度
|
||||||
// 发射参数
|
// 发射参数
|
||||||
#define ONE_BULLET_DELTA_ANGLE 36 // 发射一发弹丸拨盘转动的距离,由机械设计图纸给出
|
#define ONE_BULLET_DELTA_ANGLE 51.0f // 发射一发弹丸拨盘转动的距离,由机械设计图纸给出
|
||||||
#define REDUCTION_RATIO_LOADER 49.0f // 拨盘电机的减速比,英雄需要修改为3508的19.0f
|
#define REDUCTION_RATIO_LOADER 36.0f // 拨盘电机的减速比,英雄需要修改为3508的19.0f
|
||||||
#define NUM_PER_CIRCLE 10 // 拨盘一圈的装载量
|
#define NUM_PER_CIRCLE 7 // 拨盘一圈的装载量
|
||||||
// 机器人底盘修改的参数,单位为mm(毫米)
|
// 机器人底盘修改的参数,单位为mm(毫米)
|
||||||
#define WHEEL_BASE 350 // 纵向轴距(前进后退方向)
|
#define WHEEL_BASE 350 // 纵向轴距(前进后退方向)
|
||||||
#define TRACK_WIDTH 300 // 横向轮距(左右平移方向)
|
#define TRACK_WIDTH 300 // 横向轮距(左右平移方向)
|
||||||
@@ -154,7 +154,7 @@ typedef struct
|
|||||||
chassis_mode_e chassis_mode;
|
chassis_mode_e chassis_mode;
|
||||||
int chassis_speed_buff;
|
int chassis_speed_buff;
|
||||||
// UI部分
|
// UI部分
|
||||||
// ...
|
uint8_t robot_level; // 机器人等级
|
||||||
|
|
||||||
} Chassis_Ctrl_Cmd_s;
|
} Chassis_Ctrl_Cmd_s;
|
||||||
|
|
||||||
@@ -178,6 +178,7 @@ typedef struct
|
|||||||
Bullet_Speed_e bullet_speed; // 弹速枚举
|
Bullet_Speed_e bullet_speed; // 弹速枚举
|
||||||
uint8_t rest_heat;
|
uint8_t rest_heat;
|
||||||
float shoot_rate; // 连续发射的射频,unit per s,发/秒
|
float shoot_rate; // 连续发射的射频,unit per s,发/秒
|
||||||
|
float dead_time; // 每发弹丸的间隔时间,unit ms,毫秒
|
||||||
} Shoot_Ctrl_Cmd_s;
|
} Shoot_Ctrl_Cmd_s;
|
||||||
|
|
||||||
/* ----------------gimbal/shoot/chassis发布的反馈数据----------------*/
|
/* ----------------gimbal/shoot/chassis发布的反馈数据----------------*/
|
||||||
@@ -207,7 +208,8 @@ typedef struct
|
|||||||
{
|
{
|
||||||
attitude_t gimbal_imu_data;
|
attitude_t gimbal_imu_data;
|
||||||
uint16_t yaw_motor_single_round_angle;
|
uint16_t yaw_motor_single_round_angle;
|
||||||
uint16_t yaw_motor_total_angle;
|
//uint16_t yaw_motor_total_angle;
|
||||||
|
float yaw_motor_total_angle;
|
||||||
} Gimbal_Upload_Data_s;
|
} Gimbal_Upload_Data_s;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ static Shoot_Upload_Data_s shoot_feedback_data; // 来自cmd的发射控制信
|
|||||||
|
|
||||||
// dwt定时,计算冷却用
|
// dwt定时,计算冷却用
|
||||||
static float hibernate_time = 0, dead_time = 0;
|
static float hibernate_time = 0, dead_time = 0;
|
||||||
|
//static float target_angle = 0;
|
||||||
void ShootInit()
|
void ShootInit()
|
||||||
{
|
{
|
||||||
// 左摩擦轮
|
// 左摩擦轮
|
||||||
@@ -27,16 +27,16 @@ void ShootInit()
|
|||||||
},
|
},
|
||||||
.controller_param_init_config = {
|
.controller_param_init_config = {
|
||||||
.speed_PID = {
|
.speed_PID = {
|
||||||
.Kp = 0, // 20
|
.Kp = 20, // 20
|
||||||
.Ki = 0, // 1
|
.Ki = 1, // 1
|
||||||
.Kd = 0,
|
.Kd = 0,
|
||||||
.Improve = PID_Integral_Limit,
|
.Improve = PID_Integral_Limit,
|
||||||
.IntegralLimit = 10000,
|
.IntegralLimit = 10000,
|
||||||
.MaxOut = 15000,
|
.MaxOut = 15000,
|
||||||
},
|
},
|
||||||
.current_PID = {
|
.current_PID = {
|
||||||
.Kp = 0, // 0.7
|
.Kp = 0.7, // 0.7
|
||||||
.Ki = 0, // 0.1
|
.Ki = 0.1, // 0.1
|
||||||
.Kd = 0,
|
.Kd = 0,
|
||||||
.Improve = PID_Integral_Limit,
|
.Improve = PID_Integral_Limit,
|
||||||
.IntegralLimit = 10000,
|
.IntegralLimit = 10000,
|
||||||
@@ -52,51 +52,51 @@ void ShootInit()
|
|||||||
.motor_reverse_flag = MOTOR_DIRECTION_NORMAL,
|
.motor_reverse_flag = MOTOR_DIRECTION_NORMAL,
|
||||||
},
|
},
|
||||||
.motor_type = M3508};
|
.motor_type = M3508};
|
||||||
friction_config.can_init_config.tx_id = 1,
|
friction_config.can_init_config.tx_id = 5,
|
||||||
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);
|
friction_r = DJIMotorInit(&friction_config);
|
||||||
|
|
||||||
|
friction_config.can_init_config.tx_id = 8; // 左摩擦轮,改txid和方向就行
|
||||||
|
friction_config.controller_setting_init_config.motor_reverse_flag = MOTOR_DIRECTION_REVERSE;
|
||||||
|
friction_l = DJIMotorInit(&friction_config);
|
||||||
|
|
||||||
// 拨盘电机
|
// 拨盘电机
|
||||||
Motor_Init_Config_s loader_config = {
|
Motor_Init_Config_s loader_config = {
|
||||||
.can_init_config = {
|
.can_init_config = {
|
||||||
.can_handle = &hcan2,
|
.can_handle = &hcan2,
|
||||||
.tx_id = 5,
|
.tx_id = 7,
|
||||||
},
|
},
|
||||||
.controller_param_init_config = {
|
.controller_param_init_config = {
|
||||||
.angle_PID = {
|
.angle_PID = {
|
||||||
// 如果启用位置环来控制发弹,需要较大的I值保证输出力矩的线性度否则出现接近拨出的力矩大幅下降
|
// 如果启用位置环来控制发弹,需要较大的I值保证输出力矩的线性度否则出现接近拨出的力矩大幅下降
|
||||||
.Kp = 0, // 10
|
.Kp = 12, // 10
|
||||||
.Ki = 0,
|
.Ki = 5,
|
||||||
.Kd = 0,
|
.Kd = 0,
|
||||||
.MaxOut = 200,
|
.MaxOut = 10000,
|
||||||
},
|
},
|
||||||
.speed_PID = {
|
.speed_PID = {
|
||||||
.Kp = 0, // 10
|
.Kp = 3, // 10
|
||||||
.Ki = 0, // 1
|
.Ki = 10, // 1
|
||||||
.Kd = 0,
|
.Kd = 0,
|
||||||
.Improve = PID_Integral_Limit,
|
.Improve = PID_Integral_Limit,
|
||||||
.IntegralLimit = 5000,
|
.IntegralLimit = 250,
|
||||||
.MaxOut = 5000,
|
.MaxOut = 10000,
|
||||||
},
|
},
|
||||||
.current_PID = {
|
.current_PID = {
|
||||||
.Kp = 0, // 0.7
|
.Kp = 1.5, // 0.7
|
||||||
.Ki = 0, // 0.1
|
.Ki = 0, // 0.1
|
||||||
.Kd = 0,
|
.Kd = 0,
|
||||||
.Improve = PID_Integral_Limit,
|
.Improve = PID_Integral_Limit,
|
||||||
.IntegralLimit = 5000,
|
.IntegralLimit = 5000,
|
||||||
.MaxOut = 5000,
|
.MaxOut = 10000,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
.controller_setting_init_config = {
|
.controller_setting_init_config = {
|
||||||
.angle_feedback_source = MOTOR_FEED, .speed_feedback_source = MOTOR_FEED,
|
.angle_feedback_source = MOTOR_FEED, .speed_feedback_source = MOTOR_FEED,
|
||||||
.outer_loop_type = SPEED_LOOP, // 初始化成SPEED_LOOP,让拨盘停在原地,防止拨盘上电时乱转
|
.outer_loop_type = SPEED_LOOP, // 初始化成SPEED_LOOP,让拨盘停在原地,防止拨盘上电时乱转
|
||||||
.close_loop_type = CURRENT_LOOP | SPEED_LOOP,
|
.close_loop_type = ANGLE_LOOP | SPEED_LOOP|CURRENT_LOOP,
|
||||||
.motor_reverse_flag = MOTOR_DIRECTION_NORMAL, // 注意方向设置为拨盘的拨出的击发方向
|
.motor_reverse_flag = MOTOR_DIRECTION_REVERSE, // 注意方向设置为拨盘的拨出的击发方向
|
||||||
},
|
},
|
||||||
.motor_type = M3508 // 英雄使用m3508
|
.motor_type = M2006 // 英雄使用m3508
|
||||||
};
|
};
|
||||||
loader = DJIMotorInit(&loader_config);
|
loader = DJIMotorInit(&loader_config);
|
||||||
|
|
||||||
@@ -126,8 +126,8 @@ void ShootTask()
|
|||||||
|
|
||||||
// 如果上一次触发单发或3发指令的时间加上不应期仍然大于当前时间(尚未休眠完毕),直接返回即可
|
// 如果上一次触发单发或3发指令的时间加上不应期仍然大于当前时间(尚未休眠完毕),直接返回即可
|
||||||
// 单发模式主要提供给能量机关激活使用(以及英雄的射击大部分处于单发)
|
// 单发模式主要提供给能量机关激活使用(以及英雄的射击大部分处于单发)
|
||||||
// if (hibernate_time + dead_time > DWT_GetTimeline_ms())
|
if (hibernate_time + dead_time > DWT_GetTimeline_ms())
|
||||||
// return;
|
return;
|
||||||
|
|
||||||
// 若不在休眠状态,根据robotCMD传来的控制模式进行拨盘电机参考值设定和模式切换
|
// 若不在休眠状态,根据robotCMD传来的控制模式进行拨盘电机参考值设定和模式切换
|
||||||
switch (shoot_cmd_recv.load_mode)
|
switch (shoot_cmd_recv.load_mode)
|
||||||
@@ -138,18 +138,51 @@ void ShootTask()
|
|||||||
DJIMotorSetRef(loader, 0); // 同时设定参考值为0,这样停止的速度最快
|
DJIMotorSetRef(loader, 0); // 同时设定参考值为0,这样停止的速度最快
|
||||||
break;
|
break;
|
||||||
// 单发模式,根据鼠标按下的时间,触发一次之后需要进入不响应输入的状态(否则按下的时间内可能多次进入,导致多次发射)
|
// 单发模式,根据鼠标按下的时间,触发一次之后需要进入不响应输入的状态(否则按下的时间内可能多次进入,导致多次发射)
|
||||||
case LOAD_1_BULLET: // 激活能量机关/干扰对方用,英雄用.
|
// case LOAD_1_BULLET:
|
||||||
|
// DJIMotorOuterLoop(loader, ANGLE_LOOP); // 切换到角度环
|
||||||
|
// static float last_target_angle = 0; // 存储上次的目标角度
|
||||||
|
// if (dead_time == 0) { // 第一次触发
|
||||||
|
// last_target_angle = loader->measure.total_angle;
|
||||||
|
// }
|
||||||
|
// last_target_angle += 51*36;//ONE_BULLET_DELTA_ANGLE * REDUCTION_RATIO_LOADER; // 每次都在上次目标角度基础上增加固定角度
|
||||||
|
// DJIMotorSetRef(loader, last_target_angle);
|
||||||
|
// hibernate_time = DWT_GetTimeline_ms(); // 记录触发指令的时间
|
||||||
|
// dead_time = 450;//shoot_cmd_recv.dead_time; // 完成1发弹丸发射的时间
|
||||||
|
// break;
|
||||||
|
// case LOAD_1_BULLET:
|
||||||
|
// DJIMotorOuterLoop(loader, ANGLE_LOOP);// 切换到角度环
|
||||||
|
// DJIMotorSetRef(loader, loader->measure.total_angle+51*36);
|
||||||
|
// //DJIMotorSetRef(loader, loader->measure.total_angle + ONE_BULLET_DELTA_ANGLE);
|
||||||
|
// // 控制量增加一发弹丸的角度,其中90为36减速比*1.5
|
||||||
|
// hibernate_time = DWT_GetTimeline_ms(); // 记录触发指令的时间
|
||||||
|
// dead_time = 1000; // 完成1发弹丸发射的时间
|
||||||
|
// // 记录触发指令的时间
|
||||||
|
// //dead_time = 500;
|
||||||
|
// // 完成1发弹丸发射的时间
|
||||||
|
// break;
|
||||||
|
case LOAD_1_BULLET:
|
||||||
DJIMotorOuterLoop(loader, ANGLE_LOOP);// 切换到角度环
|
DJIMotorOuterLoop(loader, ANGLE_LOOP);// 切换到角度环
|
||||||
DJIMotorSetRef(loader, loader->measure.total_angle + ONE_BULLET_DELTA_ANGLE); // 控制量增加一发弹丸的角度
|
static float target_angle = -1900;
|
||||||
|
target_angle += 51.2*36;
|
||||||
|
//float target_angle = loader->measure.total_angle + 51*36;
|
||||||
|
DJIMotorSetRef(loader, target_angle);
|
||||||
hibernate_time = DWT_GetTimeline_ms(); // 记录触发指令的时间
|
hibernate_time = DWT_GetTimeline_ms(); // 记录触发指令的时间
|
||||||
dead_time = 150; // 完成1发弹丸发射的时间
|
dead_time = 450; // 完成1发弹丸发射的时间
|
||||||
break;
|
break;
|
||||||
// 三连发,如果不需要后续可能删除
|
// 三连发,如果不需要后续可能删除
|
||||||
case LOAD_3_BULLET:
|
case LOAD_3_BULLET:
|
||||||
DJIMotorOuterLoop(loader, ANGLE_LOOP); // 切换到速度环
|
// DJIMotorOuterLoop(loader, ANGLE_LOOP); // 切换到速度环
|
||||||
DJIMotorSetRef(loader, loader->measure.total_angle + 3 * ONE_BULLET_DELTA_ANGLE); // 增加3发
|
// DJIMotorSetRef(loader, loader->measure.total_angle + 3 * ONE_BULLET_DELTA_ANGLE); // 增加3发
|
||||||
|
// hibernate_time = DWT_GetTimeline_ms(); // 记录触发指令的时间
|
||||||
|
// dead_time = 300; // 完成3发弹丸发射的时间
|
||||||
|
// break;
|
||||||
|
DJIMotorOuterLoop(loader, ANGLE_LOOP);// 切换到角度环.
|
||||||
|
//static float target_angle = -1872;
|
||||||
|
target_angle += (51.2*36)*3;
|
||||||
|
//float target_angle = loader->measure.total_angle + 51*36;
|
||||||
|
DJIMotorSetRef(loader, target_angle);
|
||||||
hibernate_time = DWT_GetTimeline_ms(); // 记录触发指令的时间
|
hibernate_time = DWT_GetTimeline_ms(); // 记录触发指令的时间
|
||||||
dead_time = 300; // 完成3发弹丸发射的时间
|
dead_time = 700; // 完成3发弹丸发射的时间
|
||||||
break;
|
break;
|
||||||
// 连发模式,对速度闭环,射频后续修改为可变,目前固定为1Hz
|
// 连发模式,对速度闭环,射频后续修改为可变,目前固定为1Hz
|
||||||
case LOAD_BURSTFIRE:
|
case LOAD_BURSTFIRE:
|
||||||
@@ -175,16 +208,16 @@ void ShootTask()
|
|||||||
switch (shoot_cmd_recv.bullet_speed)
|
switch (shoot_cmd_recv.bullet_speed)
|
||||||
{
|
{
|
||||||
case SMALL_AMU_15:
|
case SMALL_AMU_15:
|
||||||
DJIMotorSetRef(friction_l, 0);
|
DJIMotorSetRef(friction_l, 30000);
|
||||||
DJIMotorSetRef(friction_r, 0);
|
DJIMotorSetRef(friction_r, 30000);
|
||||||
break;
|
break;
|
||||||
case SMALL_AMU_18:
|
case SMALL_AMU_18:
|
||||||
DJIMotorSetRef(friction_l, 0);
|
DJIMotorSetRef(friction_l, 30000);
|
||||||
DJIMotorSetRef(friction_r, 0);
|
DJIMotorSetRef(friction_r, 30000);
|
||||||
break;
|
break;
|
||||||
case SMALL_AMU_30:
|
case SMALL_AMU_30:
|
||||||
DJIMotorSetRef(friction_l, 0);
|
DJIMotorSetRef(friction_l, 50000);
|
||||||
DJIMotorSetRef(friction_r, 0);
|
DJIMotorSetRef(friction_r, 50000);
|
||||||
break;
|
break;
|
||||||
default: // 当前为了调试设定的默认值4000,因为还没有加入裁判系统无法读取弹速.
|
default: // 当前为了调试设定的默认值4000,因为还没有加入裁判系统无法读取弹速.
|
||||||
DJIMotorSetRef(friction_l, 30000);
|
DJIMotorSetRef(friction_l, 30000);
|
||||||
|
|||||||
@@ -199,8 +199,8 @@ void IMU_QuaternionEKF_Update(float gx, float gy, float gz, float ax, float ay,
|
|||||||
|
|
||||||
// 利用四元数反解欧拉角
|
// 利用四元数反解欧拉角
|
||||||
QEKF_INS.Yaw = atan2f(2.0f * (QEKF_INS.q[0] * QEKF_INS.q[3] + QEKF_INS.q[1] * QEKF_INS.q[2]), 2.0f * (QEKF_INS.q[0] * QEKF_INS.q[0] + QEKF_INS.q[1] * QEKF_INS.q[1]) - 1.0f) * 57.295779513f;
|
QEKF_INS.Yaw = atan2f(2.0f * (QEKF_INS.q[0] * QEKF_INS.q[3] + QEKF_INS.q[1] * QEKF_INS.q[2]), 2.0f * (QEKF_INS.q[0] * QEKF_INS.q[0] + QEKF_INS.q[1] * QEKF_INS.q[1]) - 1.0f) * 57.295779513f;
|
||||||
QEKF_INS.Pitch = atan2f(2.0f * (QEKF_INS.q[0] * QEKF_INS.q[1] + QEKF_INS.q[2] * QEKF_INS.q[3]), 2.0f * (QEKF_INS.q[0] * QEKF_INS.q[0] + QEKF_INS.q[3] * QEKF_INS.q[3]) - 1.0f) * 57.295779513f;
|
QEKF_INS.Pitch = -asinf(-2.0f * (QEKF_INS.q[1] * QEKF_INS.q[3] - QEKF_INS.q[0] * QEKF_INS.q[2])) * 57.295779513f;
|
||||||
QEKF_INS.Roll = asinf(-2.0f * (QEKF_INS.q[1] * QEKF_INS.q[3] - QEKF_INS.q[0] * QEKF_INS.q[2])) * 57.295779513f;
|
QEKF_INS.Roll = atan2f(2.0f * (QEKF_INS.q[0] * QEKF_INS.q[1] + QEKF_INS.q[2] * QEKF_INS.q[3]), 2.0f * (QEKF_INS.q[0] * QEKF_INS.q[0] + QEKF_INS.q[3] * QEKF_INS.q[3]) - 1.0f) * 57.295779513f;
|
||||||
|
|
||||||
// get Yaw total, yaw数据可能会超过360,处理一下方便其他功能使用(如小陀螺)
|
// get Yaw total, yaw数据可能会超过360,处理一下方便其他功能使用(如小陀螺)
|
||||||
if (QEKF_INS.Yaw - QEKF_INS.YawAngleLast > 180.0f)
|
if (QEKF_INS.Yaw - QEKF_INS.YawAngleLast > 180.0f)
|
||||||
|
|||||||
@@ -135,7 +135,6 @@ void INS_Task(void)
|
|||||||
INS.Gyro[X] = BMI088.Gyro[X];
|
INS.Gyro[X] = BMI088.Gyro[X];
|
||||||
INS.Gyro[Y] = BMI088.Gyro[Y];
|
INS.Gyro[Y] = BMI088.Gyro[Y];
|
||||||
INS.Gyro[Z] = BMI088.Gyro[Z];
|
INS.Gyro[Z] = BMI088.Gyro[Z];
|
||||||
|
|
||||||
// demo function,用于修正安装误差,可以不管,本demo暂时没用
|
// demo function,用于修正安装误差,可以不管,本demo暂时没用
|
||||||
IMU_Param_Correction(&IMU_Param, INS.Gyro, INS.Accel);
|
IMU_Param_Correction(&IMU_Param, INS.Gyro, INS.Accel);
|
||||||
|
|
||||||
|
|||||||
@@ -106,7 +106,36 @@ static void MotorSenderGrouping(DJIMotorInstance *motor, CAN_Init_Config_s *conf
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case DM4310:
|
||||||
|
if (motor_id < 4) // 根据ID分组
|
||||||
|
{
|
||||||
|
motor_send_num = motor_id;
|
||||||
|
motor_grouping = config->can_handle == &hcan2 ? 1 : 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
motor_send_num = motor_id - 4;
|
||||||
|
motor_grouping = config->can_handle == &hcan2 ? 0 : 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算接收id并设置分组发送id
|
||||||
|
config->rx_id = 0x300 + motor_id + 1; // 把ID+1,进行分组设置
|
||||||
|
sender_enable_flag[motor_grouping] = 1; // 设置发送标志位,防止发送空帧
|
||||||
|
motor->message_num = motor_send_num;
|
||||||
|
motor->sender_group = motor_grouping;
|
||||||
|
|
||||||
|
// 检查是否发生id冲突
|
||||||
|
for (size_t i = 0; i < idx; ++i)
|
||||||
|
{
|
||||||
|
if (dji_motor_instance[i]->motor_can_instance->can_handle == config->can_handle && dji_motor_instance[i]->motor_can_instance->rx_id == config->rx_id)
|
||||||
|
{
|
||||||
|
LOGERROR("[dji_motor] ID crash. Check in debug mode, add dji_motor_instance to watch to get more information.");
|
||||||
|
uint16_t can_bus = config->can_handle == &hcan2 ? 1 : 2;
|
||||||
|
while (1) // 6020的id 1-4和2006/3508的id 5-8会发生冲突(若有注册,即1!5,2!6,3!7,4!8) (1!5!,LTC! (((不是)
|
||||||
|
LOGERROR("[dji_motor] id [%d], can_bus [%d]", config->rx_id, can_bus);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
default: // other motors should not be registered here
|
default: // other motors should not be registered here
|
||||||
while (1)
|
while (1)
|
||||||
LOGERROR("[dji_motor]You must not register other motors using the API of DJI motor."); // 其他电机不应该在这里注册
|
LOGERROR("[dji_motor]You must not register other motors using the API of DJI motor."); // 其他电机不应该在这里注册
|
||||||
@@ -292,7 +321,6 @@ void DJIMotorControl()
|
|||||||
// 获取最终输出
|
// 获取最终输出
|
||||||
set = (int16_t)pid_ref;
|
set = (int16_t)pid_ref;
|
||||||
|
|
||||||
|
|
||||||
// 分组填入发送数据
|
// 分组填入发送数据
|
||||||
group = motor->sender_group;
|
group = motor->sender_group;
|
||||||
num = motor->message_num;
|
num = motor->message_num;
|
||||||
@@ -301,7 +329,7 @@ void DJIMotorControl()
|
|||||||
|
|
||||||
// 若该电机处于停止状态,直接将buff置零
|
// 若该电机处于停止状态,直接将buff置零
|
||||||
if (motor->stop_flag == MOTOR_STOP)
|
if (motor->stop_flag == MOTOR_STOP)
|
||||||
memset(sender_assignment[group].tx_buff + 2 * num, 0, 2u);
|
memset(sender_assignment[group].tx_buff + 2 * num, 0, sizeof(uint16_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 遍历flag,检查是否要发送这一帧报文
|
// 遍历flag,检查是否要发送这一帧报文
|
||||||
|
|||||||
@@ -105,7 +105,6 @@ void DJIMotorChangeFeed(DJIMotorInstance *motor, Closeloop_Type_e loop, Feedback
|
|||||||
* @brief 该函数被motor_task调用运行在rtos上,motor_stask内通过osDelay()确定控制频率
|
* @brief 该函数被motor_task调用运行在rtos上,motor_stask内通过osDelay()确定控制频率
|
||||||
*/
|
*/
|
||||||
void DJIMotorControl();
|
void DJIMotorControl();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 停止电机,注意不是将设定值设为零,而是直接给电机发送的电流值置零
|
* @brief 停止电机,注意不是将设定值设为零,而是直接给电机发送的电流值置零
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ static Graph_Data_t UI_shoot_line[10]; // 射击准线
|
|||||||
static Graph_Data_t UI_Energy[3]; // 电容能量条
|
static Graph_Data_t UI_Energy[3]; // 电容能量条
|
||||||
static String_Data_t UI_State_sta[6]; // 机器人状态,静态只需画一次
|
static String_Data_t UI_State_sta[6]; // 机器人状态,静态只需画一次
|
||||||
static String_Data_t UI_State_dyn[6]; // 机器人状态,动态先add才能change
|
static String_Data_t UI_State_dyn[6]; // 机器人状态,动态先add才能change
|
||||||
static uint32_t shoot_line_location[10] = {540, 960, 490, 515, 565};
|
static uint32_t shoot_line_location[10] = {525, 950, 490, 515, 565};
|
||||||
|
|
||||||
void MyUIInit()
|
void MyUIInit()
|
||||||
{
|
{
|
||||||
@@ -66,19 +66,19 @@ void MyUIInit()
|
|||||||
while (referee_recv_info->GameRobotState.robot_id == 0)
|
while (referee_recv_info->GameRobotState.robot_id == 0)
|
||||||
osDelay(100); // 若还未收到裁判系统数据,等待一段时间后再检查
|
osDelay(100); // 若还未收到裁判系统数据,等待一段时间后再检查
|
||||||
|
|
||||||
DeterminRobotID(); // 确定ui要发送到的目标客户端
|
DeterminRobotID(); // 确定ui要发送到的目标客户端.
|
||||||
UIDelete(&referee_recv_info->referee_id, UI_Data_Del_ALL, 0); // 清空UI
|
UIDelete(&referee_recv_info->referee_id, UI_Data_Del_ALL, 0); // 清空UI
|
||||||
|
|
||||||
// 绘制发射基准线
|
// 绘制发射基准线
|
||||||
UILineDraw(&UI_shoot_line[0], "sl0", UI_Graph_ADD, 7, UI_Color_White, 3, 710, shoot_line_location[0], 1210, shoot_line_location[0]);
|
//UILineDraw(&UI_shoot_line[0], "sl0", UI_Graph_ADD, 7, UI_Color_White, 3, 710, shoot_line_location[0], 1210, shoot_line_location[0]);
|
||||||
UILineDraw(&UI_shoot_line[1], "sl1", UI_Graph_ADD, 7, UI_Color_White, 3, shoot_line_location[1], 340, shoot_line_location[1], 740);
|
UILineDraw(&UI_shoot_line[1], "sl1", UI_Graph_ADD, 7, UI_Color_White, 3, shoot_line_location[1], 340, shoot_line_location[1], 740);
|
||||||
UILineDraw(&UI_shoot_line[2], "sl2", UI_Graph_ADD, 7, UI_Color_Yellow, 2, 810, shoot_line_location[2], 1110, shoot_line_location[2]);
|
UILineDraw(&UI_shoot_line[2], "sl2", UI_Graph_ADD, 7, UI_Color_Yellow, 2, 810, shoot_line_location[2], 1110, shoot_line_location[2]);
|
||||||
UILineDraw(&UI_shoot_line[3], "sl3", UI_Graph_ADD, 7, UI_Color_Yellow, 2, 810, shoot_line_location[3], 1110, shoot_line_location[3]);
|
UILineDraw(&UI_shoot_line[3], "sl3", UI_Graph_ADD, 7, UI_Color_Yellow, 2, 860, 475, 1060, 475);
|
||||||
UILineDraw(&UI_shoot_line[4], "sl4", UI_Graph_ADD, 7, UI_Color_Yellow, 2, 810, shoot_line_location[4], 1110, shoot_line_location[4]);
|
//UILineDraw(&UI_shoot_line[4], "sl4", UI_Graph_ADD, 7, UI_Color_Yellow, 2, 810, shoot_line_location[4], 1110, shoot_line_location[4]);
|
||||||
UIGraphRefresh(&referee_recv_info->referee_id, 5, UI_shoot_line[0], UI_shoot_line[1], UI_shoot_line[2], UI_shoot_line[3], UI_shoot_line[4]);
|
UIGraphRefresh(&referee_recv_info->referee_id, 5, UI_shoot_line[0], UI_shoot_line[1], UI_shoot_line[2], UI_shoot_line[3], UI_shoot_line[4]);
|
||||||
|
|
||||||
// 绘制车辆状态标志指示
|
// 绘制车辆状态标志指示
|
||||||
UICharDraw(&UI_State_sta[0], "ss0", UI_Graph_ADD, 8, UI_Color_Main, 15, 2, 150, 750, "chassis:");
|
UICharDraw(&UI_State_sta[0], "ss0", UI_Graph_ADD, 8, UI_Color_Main, 15, 2, 150, 750, "level:");
|
||||||
UICharRefresh(&referee_recv_info->referee_id, UI_State_sta[0]);
|
UICharRefresh(&referee_recv_info->referee_id, UI_State_sta[0]);
|
||||||
UICharDraw(&UI_State_sta[1], "ss1", UI_Graph_ADD, 8, UI_Color_Yellow, 15, 2, 150, 700, "gimbal:");
|
UICharDraw(&UI_State_sta[1], "ss1", UI_Graph_ADD, 8, UI_Color_Yellow, 15, 2, 150, 700, "gimbal:");
|
||||||
UICharRefresh(&referee_recv_info->referee_id, UI_State_sta[1]);
|
UICharRefresh(&referee_recv_info->referee_id, UI_State_sta[1]);
|
||||||
@@ -91,7 +91,7 @@ void MyUIInit()
|
|||||||
|
|
||||||
// 绘制车辆状态标志,动态
|
// 绘制车辆状态标志,动态
|
||||||
// 由于初始化时xxx_last_mode默认为0,所以此处对应UI也应该设为0时对应的UI,防止模式不变的情况下无法置位flag,导致UI无法刷新
|
// 由于初始化时xxx_last_mode默认为0,所以此处对应UI也应该设为0时对应的UI,防止模式不变的情况下无法置位flag,导致UI无法刷新
|
||||||
UICharDraw(&UI_State_dyn[0], "sd0", UI_Graph_ADD, 8, UI_Color_Main, 15, 2, 270, 750, "zeroforce");
|
UICharDraw(&UI_State_dyn[0], "sd0", UI_Graph_ADD, 8, UI_Color_Main, 15, 2, 270, 750, "1");
|
||||||
UICharRefresh(&referee_recv_info->referee_id, UI_State_dyn[0]);
|
UICharRefresh(&referee_recv_info->referee_id, UI_State_dyn[0]);
|
||||||
UICharDraw(&UI_State_dyn[1], "sd1", UI_Graph_ADD, 8, UI_Color_Yellow, 15, 2, 270, 700, "zeroforce");
|
UICharDraw(&UI_State_dyn[1], "sd1", UI_Graph_ADD, 8, UI_Color_Yellow, 15, 2, 270, 700, "zeroforce");
|
||||||
UICharRefresh(&referee_recv_info->referee_id, UI_State_dyn[1]);
|
UICharRefresh(&referee_recv_info->referee_id, UI_State_dyn[1]);
|
||||||
@@ -116,7 +116,7 @@ void MyUIInit()
|
|||||||
UIGraphRefresh(&referee_recv_info->referee_id, 2, UI_Energy[1], UI_Energy[2]);
|
UIGraphRefresh(&referee_recv_info->referee_id, 2, UI_Energy[1], UI_Energy[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 测试用函数,实现模式自动变化,用于检查该任务和裁判系统是否连接正常
|
// 测试用函数,实现模式自动变化,用于检查该任务和裁判系统是否连接正常.
|
||||||
static uint8_t count = 0;
|
static uint8_t count = 0;
|
||||||
static uint16_t count1 = 0;
|
static uint16_t count1 = 0;
|
||||||
static void RobotModeTest(Referee_Interactive_info_t *_Interactive_data) // 测试用函数,实现模式自动变化
|
static void RobotModeTest(Referee_Interactive_info_t *_Interactive_data) // 测试用函数,实现模式自动变化
|
||||||
@@ -176,27 +176,15 @@ static void RobotModeTest(Referee_Interactive_info_t *_Interactive_data) // 测
|
|||||||
static void MyUIRefresh(referee_info_t *referee_recv_info, Referee_Interactive_info_t *_Interactive_data)
|
static void MyUIRefresh(referee_info_t *referee_recv_info, Referee_Interactive_info_t *_Interactive_data)
|
||||||
{
|
{
|
||||||
UIChangeCheck(_Interactive_data);
|
UIChangeCheck(_Interactive_data);
|
||||||
// chassis
|
// robot level
|
||||||
if (_Interactive_data->Referee_Interactive_Flag.chassis_flag == 1)
|
if (_Interactive_data->Referee_Interactive_Flag.robot_level_flag == 1)
|
||||||
{
|
{
|
||||||
switch (_Interactive_data->chassis_mode)
|
char level_str[2];
|
||||||
{
|
level_str[0] = '0' + _Interactive_data->robot_level;
|
||||||
case CHASSIS_ZERO_FORCE:
|
level_str[1] = '\0';
|
||||||
UICharDraw(&UI_State_dyn[0], "sd0", UI_Graph_Change, 8, UI_Color_Main, 15, 2, 270, 750, "zeroforce");
|
UICharDraw(&UI_State_dyn[0], "sd0", UI_Graph_Change, 8, UI_Color_Main, 15, 2, 270, 750, level_str);
|
||||||
break;
|
|
||||||
case CHASSIS_ROTATE:
|
|
||||||
UICharDraw(&UI_State_dyn[0], "sd0", UI_Graph_Change, 8, UI_Color_Main, 15, 2, 270, 750, "rotate ");
|
|
||||||
// 此处注意字数对齐问题,字数相同才能覆盖掉
|
|
||||||
break;
|
|
||||||
case CHASSIS_NO_FOLLOW:
|
|
||||||
UICharDraw(&UI_State_dyn[0], "sd0", UI_Graph_Change, 8, UI_Color_Main, 15, 2, 270, 750, "nofollow ");
|
|
||||||
break;
|
|
||||||
case CHASSIS_FOLLOW_GIMBAL_YAW:
|
|
||||||
UICharDraw(&UI_State_dyn[0], "sd0", UI_Graph_Change, 8, UI_Color_Main, 15, 2, 270, 750, "follow ");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
UICharRefresh(&referee_recv_info->referee_id, UI_State_dyn[0]);
|
UICharRefresh(&referee_recv_info->referee_id, UI_State_dyn[0]);
|
||||||
_Interactive_data->Referee_Interactive_Flag.chassis_flag = 0;
|
_Interactive_data->Referee_Interactive_Flag.robot_level_flag = 0;
|
||||||
}
|
}
|
||||||
// gimbal
|
// gimbal
|
||||||
if (_Interactive_data->Referee_Interactive_Flag.gimbal_flag == 1)
|
if (_Interactive_data->Referee_Interactive_Flag.gimbal_flag == 1)
|
||||||
@@ -261,6 +249,12 @@ static void MyUIRefresh(referee_info_t *referee_recv_info, Referee_Interactive_i
|
|||||||
*/
|
*/
|
||||||
static void UIChangeCheck(Referee_Interactive_info_t *_Interactive_data)
|
static void UIChangeCheck(Referee_Interactive_info_t *_Interactive_data)
|
||||||
{
|
{
|
||||||
|
if (_Interactive_data->robot_level != _Interactive_data->robot_last_level)
|
||||||
|
{
|
||||||
|
_Interactive_data->Referee_Interactive_Flag.robot_level_flag = 1;
|
||||||
|
_Interactive_data->robot_last_level = _Interactive_data->robot_level;
|
||||||
|
}
|
||||||
|
|
||||||
if (_Interactive_data->chassis_mode != _Interactive_data->chassis_last_mode)
|
if (_Interactive_data->chassis_mode != _Interactive_data->chassis_last_mode)
|
||||||
{
|
{
|
||||||
_Interactive_data->Referee_Interactive_Flag.chassis_flag = 1;
|
_Interactive_data->Referee_Interactive_Flag.chassis_flag = 1;
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ typedef struct
|
|||||||
uint32_t lid_flag : 1;
|
uint32_t lid_flag : 1;
|
||||||
uint32_t friction_flag : 1;
|
uint32_t friction_flag : 1;
|
||||||
uint32_t Power_flag : 1;
|
uint32_t Power_flag : 1;
|
||||||
|
uint32_t robot_level_flag : 1;
|
||||||
} Referee_Interactive_Flag_t;
|
} Referee_Interactive_Flag_t;
|
||||||
|
|
||||||
// 此结构体包含UI绘制与机器人车间通信的需要的其他非裁判系统数据
|
// 此结构体包含UI绘制与机器人车间通信的需要的其他非裁判系统数据
|
||||||
@@ -61,6 +62,7 @@ typedef struct
|
|||||||
{
|
{
|
||||||
Referee_Interactive_Flag_t Referee_Interactive_Flag;
|
Referee_Interactive_Flag_t Referee_Interactive_Flag;
|
||||||
// 为UI绘制以及交互数据所用
|
// 为UI绘制以及交互数据所用
|
||||||
|
uint8_t robot_level; // 机器人等级
|
||||||
chassis_mode_e chassis_mode; // 底盘模式
|
chassis_mode_e chassis_mode; // 底盘模式
|
||||||
gimbal_mode_e gimbal_mode; // 云台模式
|
gimbal_mode_e gimbal_mode; // 云台模式
|
||||||
shoot_mode_e shoot_mode; // 发射模式设置
|
shoot_mode_e shoot_mode; // 发射模式设置
|
||||||
@@ -69,6 +71,7 @@ typedef struct
|
|||||||
Chassis_Power_Data_s Chassis_Power_Data; // 功率控制
|
Chassis_Power_Data_s Chassis_Power_Data; // 功率控制
|
||||||
|
|
||||||
// 上一次的模式,用于flag判断
|
// 上一次的模式,用于flag判断
|
||||||
|
uint8_t robot_last_level;
|
||||||
chassis_mode_e chassis_last_mode;
|
chassis_mode_e chassis_last_mode;
|
||||||
gimbal_mode_e gimbal_last_mode;
|
gimbal_mode_e gimbal_last_mode;
|
||||||
shoot_mode_e shoot_last_mode;
|
shoot_mode_e shoot_last_mode;
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ static void sbus_to_rc(const uint8_t *sbus_buf)
|
|||||||
rc_ctrl[TEMP].rc.rocker_l_ = (((sbus_buf[2] >> 6) | (sbus_buf[3] << 2) | (sbus_buf[4] << 10)) & 0x07ff) - RC_CH_VALUE_OFFSET; //!< Channel 2
|
rc_ctrl[TEMP].rc.rocker_l_ = (((sbus_buf[2] >> 6) | (sbus_buf[3] << 2) | (sbus_buf[4] << 10)) & 0x07ff) - RC_CH_VALUE_OFFSET; //!< Channel 2
|
||||||
rc_ctrl[TEMP].rc.rocker_l1 = (((sbus_buf[4] >> 1) | (sbus_buf[5] << 7)) & 0x07ff) - RC_CH_VALUE_OFFSET; //!< Channel 3
|
rc_ctrl[TEMP].rc.rocker_l1 = (((sbus_buf[4] >> 1) | (sbus_buf[5] << 7)) & 0x07ff) - RC_CH_VALUE_OFFSET; //!< Channel 3
|
||||||
rc_ctrl[TEMP].rc.dial = ((sbus_buf[16] | (sbus_buf[17] << 8)) & 0x07FF) - RC_CH_VALUE_OFFSET;
|
rc_ctrl[TEMP].rc.dial = ((sbus_buf[16] | (sbus_buf[17] << 8)) & 0x07FF) - RC_CH_VALUE_OFFSET;
|
||||||
rc_ctrl[TEMP].rc.rocker_l_= rc_ctrl[TEMP].rc.rocker_l_;
|
rc_ctrl[TEMP].rc.rocker_l_= rc_ctrl[TEMP].rc.rocker_l_+5.5;
|
||||||
// 左侧拨轮
|
// 左侧拨轮
|
||||||
RectifyRCjoystick();
|
RectifyRCjoystick();
|
||||||
// 开关,0左1右
|
// 开关,0左1右
|
||||||
|
|||||||
@@ -1,15 +1,12 @@
|
|||||||
/*
|
/*
|
||||||
* @Descripttion:
|
* @Descripttion: 适配群星战队协议的超级电容模块
|
||||||
* @version:
|
* @version: V2.0
|
||||||
* @Author: Chenfu
|
|
||||||
* @Date: 2022-12-02 21:32:47
|
|
||||||
* @LastEditTime: 2022-12-05 15:29:49
|
|
||||||
*/
|
*/
|
||||||
#include "super_cap.h"
|
#include "super_cap.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "stdlib.h"
|
#include "stdlib.h"
|
||||||
|
|
||||||
static SuperCapInstance *super_cap_instance = NULL; // 可以由app保存此指针
|
static SuperCapInstance *super_cap_instance = NULL;
|
||||||
|
|
||||||
static void SuperCapRxCallback(CANInstance *_instance)
|
static void SuperCapRxCallback(CANInstance *_instance)
|
||||||
{
|
{
|
||||||
@@ -17,9 +14,14 @@ static void SuperCapRxCallback(CANInstance *_instance)
|
|||||||
SuperCap_Msg_s *Msg;
|
SuperCap_Msg_s *Msg;
|
||||||
rxbuff = _instance->rx_buff;
|
rxbuff = _instance->rx_buff;
|
||||||
Msg = &super_cap_instance->cap_msg;
|
Msg = &super_cap_instance->cap_msg;
|
||||||
Msg->vol = (uint16_t)(rxbuff[0] << 8 | rxbuff[1]);
|
|
||||||
Msg->current = (uint16_t)(rxbuff[2] << 8 | rxbuff[3]);
|
// 按照新协议解析接收数据
|
||||||
Msg->power = (uint16_t)(rxbuff[4] << 8 | rxbuff[5]);
|
Msg->ready = (SuperCapReadyEnum)rxbuff[0];
|
||||||
|
Msg->state = (SuperCapStateEnum)rxbuff[1];
|
||||||
|
Msg->energy = rxbuff[2];
|
||||||
|
Msg->chassis_power = (uint16_t)(rxbuff[3] << 1); // 左移一位还原量程
|
||||||
|
Msg->bat_voltage = rxbuff[4];
|
||||||
|
Msg->bat_power = rxbuff[5];
|
||||||
}
|
}
|
||||||
|
|
||||||
SuperCapInstance *SuperCapInit(SuperCap_Init_Config_s *supercap_config)
|
SuperCapInstance *SuperCapInit(SuperCap_Init_Config_s *supercap_config)
|
||||||
@@ -32,12 +34,26 @@ SuperCapInstance *SuperCapInit(SuperCap_Init_Config_s *supercap_config)
|
|||||||
return super_cap_instance;
|
return super_cap_instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SuperCapSend(SuperCapInstance *instance, uint8_t *data)
|
void SuperCapSend(SuperCapInstance *instance, SuperCap_TxMsg_s *tx_data)
|
||||||
{
|
{
|
||||||
memcpy(instance->can_ins->tx_buff, data, 8);
|
uint8_t *txbuff = instance->can_ins->tx_buff;
|
||||||
|
|
||||||
|
// 按照新协议装载发送数据
|
||||||
|
txbuff[0] = tx_data->Enable;
|
||||||
|
txbuff[1] = tx_data->Charge;
|
||||||
|
txbuff[2] = tx_data->Powerlimit - instance->power_offset; // 计算功率补偿
|
||||||
|
txbuff[3] = tx_data->ChargePower;
|
||||||
|
|
||||||
CANTransmit(instance->can_ins, 1);
|
CANTransmit(instance->can_ins, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SuperCapSetPowerOffset(SuperCapInstance *instance, uint8_t offset)
|
||||||
|
{
|
||||||
|
if (instance != NULL) {
|
||||||
|
instance->power_offset = offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SuperCap_Msg_s SuperCapGet(SuperCapInstance *instance)
|
SuperCap_Msg_s SuperCapGet(SuperCapInstance *instance)
|
||||||
{
|
{
|
||||||
return instance->cap_msg;
|
return instance->cap_msg;
|
||||||
|
|||||||
@@ -1,29 +1,61 @@
|
|||||||
/*
|
/*
|
||||||
* @Descripttion:
|
* @Descripttion: 适配群星战队协议的超级电容模块
|
||||||
* @version:
|
* @version: V2.0
|
||||||
* @Author: Chenfu
|
|
||||||
* @Date: 2022-12-02 21:32:47
|
|
||||||
* @LastEditTime: 2022-12-05 15:25:46
|
|
||||||
*/
|
*/
|
||||||
#ifndef SUPER_CAP_H
|
#ifndef SUPER_CAP_H
|
||||||
#define SUPER_CAP_H
|
#define SUPER_CAP_H
|
||||||
|
|
||||||
#include "bsp_can.h"
|
#include "bsp_can.h"
|
||||||
|
|
||||||
|
// 超级电容状态枚举(从群星战队协议移植)
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
DISCHARGE = 0, // 放电状态
|
||||||
|
CHARGE = 1, // 充电状态
|
||||||
|
WAIT = 2, // 待机状态
|
||||||
|
SOFTSTART_PROTECTION = 3, // 处于软起动状态
|
||||||
|
OVER_LOAD_PROTECTION = 4, // 超电过载保护状态
|
||||||
|
BAT_OVER_VOLTAGE_PROTECTION = 5, // 过压保护状态
|
||||||
|
BAT_UNDER_VOLTAGE_PROTECTION = 6, // 电池欠压保护
|
||||||
|
CAP_UNDER_VOLTAGE_PROTECTION = 7, // 超级电容欠压保护
|
||||||
|
OVER_TEMPERATURE_PROTECTION = 8, // 过温保护
|
||||||
|
BOOM = 9, // 超电爆炸了
|
||||||
|
} SuperCapStateEnum;
|
||||||
|
|
||||||
|
// 超级电容准备状态
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
UNREADY = 0,
|
||||||
|
READY = 1,
|
||||||
|
} SuperCapReadyEnum;
|
||||||
|
|
||||||
#pragma pack(1)
|
#pragma pack(1)
|
||||||
|
/* 接收到的超级电容信息结构体 */
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
uint16_t vol; // 电压
|
SuperCapReadyEnum ready; // 可用标志:1为可用,0为不可用
|
||||||
uint16_t current; // 电流
|
SuperCapStateEnum state; // 状态标志
|
||||||
uint16_t power; // 功率
|
uint8_t energy; // 超级电容可用能量:0-100%
|
||||||
|
uint16_t chassis_power; // 底盘功率
|
||||||
|
uint8_t bat_voltage; // 电池电压*10
|
||||||
|
uint8_t bat_power; // 电池功率
|
||||||
} SuperCap_Msg_s;
|
} SuperCap_Msg_s;
|
||||||
|
|
||||||
|
/* 需要发送给超级电容的控制信息结构体 */
|
||||||
|
typedef struct {
|
||||||
|
uint8_t Enable; // 超级电容使能。1使能,0失能
|
||||||
|
uint8_t Charge; // 超级电容充电。1充电,0放电
|
||||||
|
uint8_t Powerlimit; // 裁判系统功率限制
|
||||||
|
uint8_t ChargePower; // 超级电容充电功率
|
||||||
|
} SuperCap_TxMsg_s;
|
||||||
#pragma pack()
|
#pragma pack()
|
||||||
|
|
||||||
/* 超级电容实例 */
|
/* 超级电容实例 */
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
CANInstance *can_ins; // CAN实例
|
CANInstance *can_ins; // CAN实例
|
||||||
SuperCap_Msg_s cap_msg; // 超级电容信息
|
SuperCap_Msg_s cap_msg; // 超级电容接收信息
|
||||||
|
uint8_t power_offset; // 功率补偿值
|
||||||
} SuperCapInstance;
|
} SuperCapInstance;
|
||||||
|
|
||||||
/* 超级电容初始化配置 */
|
/* 超级电容初始化配置 */
|
||||||
@@ -34,18 +66,22 @@ typedef struct
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 初始化超级电容
|
* @brief 初始化超级电容
|
||||||
*
|
|
||||||
* @param supercap_config 超级电容初始化配置
|
|
||||||
* @return SuperCapInstance* 超级电容实例指针
|
|
||||||
*/
|
*/
|
||||||
SuperCapInstance *SuperCapInit(SuperCap_Init_Config_s *supercap_config);
|
SuperCapInstance *SuperCapInit(SuperCap_Init_Config_s *supercap_config);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 发送超级电容控制信息
|
* @brief 发送超级电容控制信息
|
||||||
*
|
|
||||||
* @param instance 超级电容实例
|
|
||||||
* @param data 超级电容控制信息
|
|
||||||
*/
|
*/
|
||||||
void SuperCapSend(SuperCapInstance *instance, uint8_t *data);
|
void SuperCapSend(SuperCapInstance *instance, SuperCap_TxMsg_s *tx_data);
|
||||||
|
|
||||||
#endif // !SUPER_CAP_Hd
|
/**
|
||||||
|
* @brief 设置超级电容功率补偿
|
||||||
|
*/
|
||||||
|
void SuperCapSetPowerOffset(SuperCapInstance *instance, uint8_t offset);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取超级电容数据
|
||||||
|
*/
|
||||||
|
SuperCap_Msg_s SuperCapGet(SuperCapInstance *instance);
|
||||||
|
|
||||||
|
#endif // !SUPER_CAP_H
|
||||||
@@ -1,21 +1,16 @@
|
|||||||
<!--
|
# super_cap (适配版)
|
||||||
* @Descripttion:
|
|
||||||
* @version:
|
|
||||||
* @Author: Chenfu
|
|
||||||
* @Date: 2022-12-02 21:32:47
|
|
||||||
* @LastEditTime: 2022-12-05 15:27:57
|
|
||||||
-->
|
|
||||||
# super_can
|
|
||||||
|
|
||||||
## 代码结构
|
## 代码结构
|
||||||
|
|
||||||
.h中放置的是数据定义和外部接口,以及协议的定义和宏,.c中包含一些私有函数。
|
.h中放置的是数据和协议枚举定义、控制接口,.c中包含CAN接收中断的回调解析以及发送打包逻辑。当前版本已完全适配群星战队的超级电容协议。
|
||||||
|
|
||||||
## 外部接口
|
## 外部接口
|
||||||
|
|
||||||
```c
|
```c
|
||||||
SuperCapInstance *SuperCapInit(SuperCap_Init_Config_s* supercap_config);
|
SuperCapInstance *SuperCapInit(SuperCap_Init_Config_s* supercap_config);
|
||||||
void SuperCapSend(SuperCapInstance *instance, uint8_t *data);
|
void SuperCapSend(SuperCapInstance *instance, SuperCap_TxMsg_s *tx_data);
|
||||||
|
void SuperCapSetPowerOffset(SuperCapInstance *instance, uint8_t offset);
|
||||||
|
SuperCap_Msg_s SuperCapGet(SuperCapInstance *instance);
|
||||||
```
|
```
|
||||||
## 私有函数和变量
|
## 私有函数和变量
|
||||||
|
|
||||||
@@ -25,7 +20,7 @@ static uint8_t *rxbuff;
|
|||||||
static void SuperCapRxCallback(can_instance *_instance)
|
static void SuperCapRxCallback(can_instance *_instance)
|
||||||
```
|
```
|
||||||
|
|
||||||
`SuperCapRxCallback()`是super cap初始化can实例时的回调函数,用于can接收中断,进行协议解析。
|
SuperCapRxCallback()是super cap初始化can实例时的回调函数,用于CAN接收中断,进行协议解析(包含底盘功率右移量程的还原等处理)。
|
||||||
|
|
||||||
## 使用范例
|
## 使用范例
|
||||||
|
|
||||||
@@ -35,20 +30,26 @@ static void SuperCapRxCallback(can_instance *_instance)
|
|||||||
SuperCap_Init_Config_s capconfig = {
|
SuperCap_Init_Config_s capconfig = {
|
||||||
.can_config = {
|
.can_config = {
|
||||||
.can_handle = &hcan1,
|
.can_handle = &hcan1,
|
||||||
.rx_id = 0x301,
|
.rx_id = 0x100, // 超级电容发给C板的ID
|
||||||
.tx_id = 0x302
|
.tx_id = 0x001 // C板发给超级电容的ID
|
||||||
},
|
}
|
||||||
.recv_data_len = 4*sizeof(uint16_t),
|
|
||||||
.send_data_len = sizeof(uint8_t)
|
|
||||||
};
|
};
|
||||||
SuperCapInstance *ins = SuperCapInit(&capconfig);
|
SuperCapInstance *ins = SuperCapInit(&capconfig);
|
||||||
|
|
||||||
|
// 如果需要设置功率补偿
|
||||||
|
SuperCapSetPowerOffset(ins, 5);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
发送通过`SuperCapSend()`,建议使用强制类型转换:
|
发送通过`SuperCapSend()`,建议使用强制类型转换:
|
||||||
|
发送控制指令时,使用 SuperCap_TxMsg_s 结构体:
|
||||||
```c
|
```c
|
||||||
uint16_t tx = 0x321;
|
SuperCap_TxMsg_s tx_cmd = {
|
||||||
SuperCapSend(ins, (uint8_t*)&tx);
|
.Enable = 1,
|
||||||
|
.Charge = 1,
|
||||||
|
.Powerlimit = 60,
|
||||||
|
.ChargePower = 40
|
||||||
|
};
|
||||||
|
SuperCapSend(ins, &tx_cmd);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user