duolun/User/module/chassis.c
2025-10-05 20:17:21 +08:00

351 lines
14 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
底盘任务
*/
/* Includes ----------------------------------------------------------------- */
#include "chassis.h"
#include "device/motor_rm.h"
#include "bsp/time.h"
#include "bsp/can.h"
#include "math.h"
#include "component/pid.h"
#include "component/filter.h"
/*舵轮舵向校准方法注释掉关于6020反馈角度的处理以及6020数据的发送这两处(define.h里有快捷方法)
进debug将四个轮子编码器朝右左右无所谓可能会导致5065方向反在解算里加个负号就行
查看6020反馈值将6020反馈值放入motor_offset中*/
/*chassis_t结构体中的内容现在有 move_vec (最终输出速度)
hopemotorout(期望的底盘输出值)舵轮解算出的各个电机的期望输出值 包括四个6020 和四个3508
final_out;(经PID计算后的实际发送给电机的实时输出值) 四个6020 四个3508
motorfeedback(电机反馈数据) 四个3508 四个6020
pid 各个电机的pid参数
ChassisImu_t pos088; 088的实时姿态
MotorOffset_t motoroffset; //5065校准数据
const Chassis_Param_t *param; //一些固定的参数
fp32 vofa_send[8]; //vofa输出数据
LowPassFilter2p_t filled[9]; //低通滤波器
float keep_angle[4]; // 保持的 6020 角度
*/
/*底盘初始化*/
int8_t chassis_init(Chassis_t *c, Chassis_Param_t *param, float target_freq)
{
if (c == NULL || param == NULL || target_freq <= 0.0f)
{
return CHASSIS_ERR; // 参数错误
}
c->param = param;
c->mode = STOP; // 默认模式为停止锁死底盘
/*初始化can*/
BSP_CAN_Init();
/*注册3508电机*/
for (int i = 0; i < 4; i++)
{
MOTOR_RM_Register(&(c->param->motor_3508_param[i]));
}
/*注册6020电机*/
for (int i = 0; i < 4; i++)
{
MOTOR_RM_Register(&(c->param->motor_6020_param[i]));
}
// 舵轮安装时的6020机械误差机械校准时1号轮在左前方所有轮的编码器朝向右面
MotorOffset_t motor_offset = {{6.28088474/M_PI*180.0f, 2.08161187/M_PI*180.0f, 2.09618473/M_PI*180.0f, 5.25465155/M_PI*180.0f}};
c->motoroffset = motor_offset;
/*对3508的速度环和6020的角速度以及位置环pid进行初始化*/
for (int i = 0; i < 4; i++)
{
PID_Init(&c->pid.chassis_3508VPID[i], KPID_MODE_NO_D, target_freq, &c->param->M3508v_param);
}
for (int i = 0; i < 4; i++)
{
PID_Init(&c->pid.chassis_6020OmegaPid[i], KPID_MODE_NO_D, target_freq, &c->param->C6020Omega_param);
PID_Init(&c->pid.chassis_6020anglePid[i], KPID_MODE_NO_D, target_freq, &c->param->C6020Angle_param);
}
/*对遥控器的xyw进行低通滤波*/
LowPassFilter2p_Init(&c->filled[0], target_freq, 20.0f); // vx
LowPassFilter2p_Init(&c->filled[1], target_freq, 20.0f); // vy
LowPassFilter2p_Init(&c->filled[2], target_freq, 20.0f); // vw
// c->set_point.yaw = 0.0f;
return CHASSIS_OK;
}
static int8_t Chassis_SetMode(Chassis_t *c, Chassis_CMD_t *c_cmd)
{
if (c == NULL)
return CHASSIS_ERR_NULL; /* 主结构体不能为空 */
for (int i = 0; i < 4; i++)
{
PID_Reset(&c->pid.chassis_3508VPID[i]);
PID_Reset(&c->pid.chassis_6020OmegaPid[i]);
PID_Reset(&c->pid.chassis_6020anglePid[i]);
}
c->mode = c_cmd->mode;
return CHASSIS_OK;
}
// 底盘解算
void Chassis_speed_calculate(Chassis_t *c, Chassis_CMD_t *c_cmd)
{
// RC模式下松开遥控器防止6020回到默认位置导致侧翻
if (c->mode == RC && fabs(c->move_vec.Vx) < 100 && fabs(c->move_vec.Vy) < 100 && fabs(c->move_vec.Vw) < 100)
{
// 如果之前不处于保持模式,则记录当前角度
if (!c->keeping_angle_flag)
{
c->keeping_angle_flag = 1; // 进入保持模式
}
// 使用保持的角度,而不是实时反馈值,速度为0
for (uint8_t i = 0; i < 4; i++)
{
c->hopemotorout.rotor6020_jiesuan_1[i] = c->keep_angle[i];
c->hopemotorout.rotor3508_jiesuan_1[i] = 0;
}
}
else
{
// 如果有速度输入,则退出保持模式
c->keeping_angle_flag = 0;
// 让保持角度实时等于进入保持阈值前的最后一次角度值
for (uint8_t i = 0; i < 4; i++)
{
c->keep_angle[i] = c->hopemotorout.rotor6020_jiesuan_1[i];
}
switch (c->mode)
{
case RC:
// const double radians = atan(1.0f * 330 / 330);
c->hopemotorout.rotor3508_jiesuan_1[0] = -sqrt((c->move_vec.Vx + c->move_vec.Vw * sin(radians)) * (c->move_vec.Vx + c->move_vec.Vw * sin(radians))
+ (c->move_vec.Vy + c->move_vec.Vw * cos(radians)) * (c->move_vec.Vy + c->move_vec.Vw * cos(radians)));
c->hopemotorout.rotor3508_jiesuan_1[1] = sqrt((c->move_vec.Vx - c->move_vec.Vw * sin(radians)) * (c->move_vec.Vx - c->move_vec.Vw * sin(radians))
+ (c->move_vec.Vy + c->move_vec.Vw * cos(radians)) * (c->move_vec.Vy + c->move_vec.Vw * cos(radians)));
c->hopemotorout.rotor3508_jiesuan_1[2] = -sqrt((c->move_vec.Vx + c->move_vec.Vw * sin(radians)) * (c->move_vec.Vx + c->move_vec.Vw * sin(radians))
+ (c->move_vec.Vy - c->move_vec.Vw * cos(radians)) * (c->move_vec.Vy - c->move_vec.Vw * cos(radians)));
c->hopemotorout.rotor3508_jiesuan_1[3] = sqrt((c->move_vec.Vx - c->move_vec.Vw * sin(radians)) * (c->move_vec.Vx - c->move_vec.Vw * sin(radians))
+ (c->move_vec.Vy - c->move_vec.Vw * cos(radians)) * (c->move_vec.Vy - c->move_vec.Vw * cos(radians)));
c->hopemotorout.rotor6020_jiesuan_1[0] = atan2((c->move_vec.Vy + c->move_vec.Vw * cos(radians)),
(c->move_vec.Vx + c->move_vec.Vw * sin(radians))) *
(180.0f / M_PI);
c->hopemotorout.rotor6020_jiesuan_1[1] = atan2((c->move_vec.Vy + c->move_vec.Vw * cos(radians)),
(c->move_vec.Vx - c->move_vec.Vw * sin(radians))) *
(180.0f / M_PI);
c->hopemotorout.rotor6020_jiesuan_1[2] = atan2((c->move_vec.Vy - c->move_vec.Vw * cos(radians)),
(c->move_vec.Vx + c->move_vec.Vw * sin(radians))) *
(180.0f / M_PI);
c->hopemotorout.rotor6020_jiesuan_1[3] = atan2((c->move_vec.Vy - c->move_vec.Vw * cos(radians)),
(c->move_vec.Vx - c->move_vec.Vw * sin(radians))) *
(180.0f / M_PI);
break;
case STOP:
for (int i = 0; i < 4; i++)
{
c->hopemotorout.rotor3508_jiesuan_1[i] = 0.0f;
}
// c->hopemotorout.rotor6020_jiesuan_1[0] = 6.26554489/M_PI*180.0f;
// c->hopemotorout.rotor6020_jiesuan_1[1] = 2.1099906/M_PI*180.0f;
// c->hopemotorout.rotor6020_jiesuan_1[2] = 2.08391285/M_PI*180.0f;
// c->hopemotorout.rotor6020_jiesuan_1[3] = 5.26845694/M_PI*180.0f;
c->hopemotorout.rotor6020_jiesuan_1[0] = -45/M_PI*180.0f;
c->hopemotorout.rotor6020_jiesuan_1[1] = 45/M_PI*180.0f;
c->hopemotorout.rotor6020_jiesuan_1[2] = -45/M_PI*180.0f;
c->hopemotorout.rotor6020_jiesuan_1[3] = 45/M_PI*180.0f;
break;
case LOCK:
for (int i = 0; i < 4; i++)
{
c->hopemotorout.rotor3508_jiesuan_1[i] = 0.0f;
}
c->hopemotorout.rotor6020_jiesuan_1[0] = 315;
c->hopemotorout.rotor6020_jiesuan_1[1] = 45;
c->hopemotorout.rotor6020_jiesuan_1[2] = 45;
c->hopemotorout.rotor6020_jiesuan_1[3] = 315;
break;
}
}
// 角度归化到0°——360°
for (uint8_t i = 0; i < 4; i++)
{
if (c->hopemotorout.rotor6020_jiesuan_1[i] < 0)
{
c->hopemotorout.rotor6020_jiesuan_1[i] += 360;
}
}
float angle_error[4]; // 角度误差
for (uint8_t i = 0; i < 4; i++)
{
angle_error[i] = c->hopemotorout.rotor6020_jiesuan_1[i] - c->motorfeedback.rotor_angle6020[i];
// 误差角度归化到-180°——+180°
while (angle_error[i] > 180)
angle_error[i] -= 360;
while (angle_error[i] < -180)
angle_error[i] += 360;
/*这里发现如果下面的c->motorfeedback.rotor_angle6020[i]+angle_error[i]变为
c->hopemotorout.rotor6020_jiesuan_1[i]会导致6020出现故障*/
if (angle_error[i] > 90 && angle_error[i] <= 180)
{
c->hopemotorout.rotor3508_jiesuan_2[i] = -c->hopemotorout.rotor3508_jiesuan_1[i];
c->hopemotorout.rotor6020_jiesuan_2[i] = c->motorfeedback.rotor_angle6020[i] + angle_error[i] - 180;
}
else if (angle_error[i] < -90 && angle_error[i] >= -180)
{
c->hopemotorout.rotor3508_jiesuan_2[i] = -c->hopemotorout.rotor3508_jiesuan_1[i];
c->hopemotorout.rotor6020_jiesuan_2[i] = c->motorfeedback.rotor_angle6020[i] + angle_error[i] + 180;
}
else
{
c->hopemotorout.rotor3508_jiesuan_2[i] = c->hopemotorout.rotor3508_jiesuan_1[i];
c->hopemotorout.rotor6020_jiesuan_2[i] = c->motorfeedback.rotor_angle6020[i] + angle_error[i];
}
}
}
int8_t Chassis_update(Chassis_t *c)
{
if (c == NULL) {
return CHASSIS_ERR_NULL; // 参数错误
}
/*更新所有电机数据*/
MOTOR_RM_UpdateAll();
/*更新电机反馈*/
for(int i=0;i<4;i++){
c->motorfeedback.rotor_angle6020[i] = ( MOTOR_GetRotorAbsAngle(&(MOTOR_RM_GetMotor(&c->param->motor_6020_param[i])->motor))/M_PI*180.0f);
c->motorfeedback.rotor_rpm6020[i] = MOTOR_GetRotorSpeed(&(MOTOR_RM_GetMotor(&c->param->motor_6020_param[i])->motor));
c->motorfeedback.rotor_rpm3508[i] = MOTOR_GetRotorSpeed(&(MOTOR_RM_GetMotor(&c->param->motor_6020_param[i])->motor));
// c->motorfeedback.rotor_angle6020[i] = MOTOR_GetRotorAbsAngle(&(MOTOR_RM_GetMotor(&c->param->motor_6020_param[i])->motor));
c->motorfeedback.rotor_angle6020[i] = fmod(c->motorfeedback.rotor_angle6020[i] - c->motoroffset.MOTOR_OFFSET[i], 360.0);
}
return CHASSIS_OK;
}
// 防止侧翻
/*具体开始上车实验之后在进行编写修改,先暂时不使用*/
void ChassisrolPrevent(Chassis_t *c)
{
}
int8_t Chassis_Control(Chassis_t *c, Chassis_CMD_t *c_cmd)
{
float chassis6020_detangle[4]; // 6020解算出的角度
if (c == NULL || c_cmd == NULL)
{
return CHASSIS_ERR_NULL; // 参数错误
}
c->dt = (BSP_TIME_Get_us() - c->last_wakeup) / 1000000.0f; /* 计算两次调用的时间间隔,单位秒 */
c->last_wakeup = BSP_TIME_Get_us();
/*设置底盘模式*/
if (Chassis_SetMode(c, c_cmd) != CHASSIS_OK)
{
return CHASSIS_ERR_MODE; /* 设置模式失败 */
}
/*根据底盘模式进行不同的控制*/
switch (c->mode)
{
case STOP:
// 停止模式
c->move_vec.Vx = 0.0f;
c->move_vec.Vy = 0.0f;
c->move_vec.Vw = 0.0f;
break;
case RC:
// 遥控模式
// c->move_vec.Vx = c_cmd->Vx * c_cmd->throttle * 1000.0f;
// c->move_vec.Vy = c_cmd->Vy * c_cmd->throttle * 1000.0f;
c->move_vec.Vx = c_cmd->Vx * 1000.0f;
c->move_vec.Vy = c_cmd->Vy * 1000.0f;
c->move_vec.Vw = c_cmd->Vw * 1000.0f;
break;
default:
return CHASSIS_ERR_MODE; /* 未知模式 */
}
/*给输出的VxVyVw进行滤波*/
c->move_vec.Vx = LowPassFilter2p_Apply(&c->filled[0], c->move_vec.Vx);
c->move_vec.Vy = LowPassFilter2p_Apply(&c->filled[1], c->move_vec.Vy);
c->move_vec.Vw = LowPassFilter2p_Apply(&c->filled[2], c->move_vec.Vw);
Chassis_speed_calculate(c, c_cmd);
for (int i = 0; i < 4; i++)
{
c->hopemotorout.motor6020_target[i] = c->hopemotorout.rotor6020_jiesuan_2[i];
chassis6020_detangle[i] = PID_Calc(&(c->pid.chassis_6020anglePid[i]), c->hopemotorout.motor6020_target[i],
c->motorfeedback.rotor_angle6020[i], 0.0f, c->dt);
c->final_out.final_6020out[i] = chassis6020_detangle[i] ; //单环控制就用这个
// c->final_out.final_6020out[i] = PID_Calc(&(c->pid.chassis_6020OmegaPid[i]), chassis6020_detangle[i],
// c->motorfeedback.rotor_rpm6020[i], 0.0f, c->dt);
c->out.rotor6020_out[i] = c->final_out.final_6020out[i];
c->hopemotorout.motor3508_target[i] = c->hopemotorout.rotor3508_jiesuan_2[i];
c->final_out.final_3508out[i] = PID_Calc(&(c->pid.chassis_3508VPID[i]), c->hopemotorout.motor3508_target[i],
c->motorfeedback.rotor_rpm3508[i], 0.0f, c->dt);
c->out.rotor3508_out[i] = c->final_out.final_3508out[i];
}
return CHASSIS_OK;
}
/*电机输出设定和发送*/
void Chassis_Setoutput(Chassis_t * c)
{
for (int i = 0; i < 4; i++)
{
MOTOR_RM_SetOutput(&(c->param->motor_3508_param[i]), c->out.rotor3508_out[i]);
MOTOR_RM_SetOutput(&(c->param->motor_6020_param[i]), c->out.rotor6020_out[i]);
}
MOTOR_RM_Ctrl(&(c->param->motor_3508_param[0]));
MOTOR_RM_Ctrl(&(c->param->motor_6020_param[0]));
/*最后这里的数据处理发送和PID计算还未处理写后面更改现在注释部分是王志城的代码*/
// #ifdef calibration
// #else
// for (uint8_t i = 0 ; i <4 ; i++){
// c->hopemotorout.motor6020_target[i]=c->hopemotorout.rotor6020_jiesuan_2[i];
// chassis6020_detangle[i] = PID_calc(&(c->pid.chassis_6020anglePid[i]),c->motorfeedback.rotor_angle6020[i],
// c->hopemotorout.motor6020_target[i]);
// c->final_out.final_6020out[i] = PID_calc(&(c->pid.chassis_6020OmegaPid[i]),c->motorfeedback.rotor_rpm6020[i],
// chassis6020_detangle[i]);
// out->chassis6020.as_array[i] = c->final_out.final_6020out[i];
// c->hopemotorout.motor5065_target[i]=c->hopemotorout.rotor5065_jiesuan_2[i];
// c->final_out.final_5065out[i]=c->hopemotorout.motor5065_target[i];
// out->chassis5065.erpm[i] = c->final_out.final_5065out[i];
// }
// #endif
}