R2_UP/User/Module/up.c
2025-04-14 21:11:43 +08:00

506 lines
13 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.

#include "up.h"
#include "gpio.h"
#include "user_math.h"
#include "bsp_buzzer.h"
#include "bsp_delay.h"
#define GEAR_RATIO_2006 (36) // 2006减速比
#define GEAR_RATIO_3508 (19)
#define CAN_MOTOR_ENC_RES 8191 // 编码器分辨率
#define MOTOR2006_ECD_TO_ANGLE (360.0 / 8191.0 / (GEAR_RATIO_2006)) //2006编码值转轴角度
#define MOTOR3508_ECD_TO_ANGLE (360.0 / 8191.0 / (GEAR_RATIO_3508)) //3508编码值转轴角度
// 定义继电器控制
#define RELAY1_TOGGLE(state) HAL_GPIO_WritePin(GPIOE, GPIO_PIN_9, (state) ? GPIO_PIN_SET : GPIO_PIN_RESET)
#define RELAY2_TOGGLE(state) HAL_GPIO_WritePin(GPIOE, GPIO_PIN_11, (state) ? GPIO_PIN_SET : GPIO_PIN_RESET)
int8_t up_init(UP_t *u,const UP_Param_t *param,float target_freq)
{
u->param = param; /*初始化参数 */
/*go电机初始化*/
GO_M8010_init();
/*pid初始化*/
PID_init (&u->pid.VESC_5065_M1 ,PID_POSITION ,&(u->param ->VESC_5065_M1_param ));
PID_init (&u->pid.VESC_5065_M2 ,PID_POSITION ,&(u->param ->VESC_5065_M2_param ));
PID_init (&u->pid .M2006_angle ,PID_POSITION ,&(u->param->M2006_angle_param ));
PID_init (&u->pid .M2006_speed ,PID_POSITION ,&(u->param->M2006_speed_param ));
PID_init (&u->pid .M3508_angle ,PID_POSITION ,&(u->param->M3508_angle_param ));
PID_init (&u->pid .M3508_speed ,PID_POSITION ,&(u->param->M3508_speed_param ));
PID_init (&u->pid .GM6020_speed,PID_POSITION ,&(u->param ->UP_GM6020_speed_param ));
PID_init (&u->pid .GM6020_angle,PID_POSITION ,&(u->param ->UP_GM6020_angle_param ));
PID_init (&u->pid .GO1_position ,PID_POSITION,&(u->param->go1_position_param ));
// for(int i=0;i<2;i++){ //go初始位置设置为0
// GO_M8010_send_data(BSP_UART_GetHandle(BSP_UART_RS485), i,u->param->go_param[i] .rev ,u->param->go_param[i] .T ,u->param->go_param[i] .W ,0,u->param->go_param [i].K_P ,u->param->go_param[i] .K_W );
// }
// 初始化上层状态机
if (!u->DribbleContext .is_initialized) { //检查是否为第一次运行状态机,运球
u->DribbleContext .DribbleConfig = u->param ->DribbleConfig_Config ;//赋值
u->DribbleContext .DribbleState = Dribble_PREPARE;
u->DribbleContext .is_initialized = 1;
}
if (!u->PitchContext .is_initialized) {
u->PitchContext .PitchConfig = u->param ->PitchConfig_Config ;//赋值
u->PitchContext .PitchState = PITCH_PREPARE; //状态更新,开始夹球
u->PitchContext .is_initialized = 1;
}
}
/*can上层状态更新*/
int8_t UP_UpdateFeedback(UP_t *u, const CAN_t *can, CMD_t *c) {
for(int i=0;i<2;i++){ //go初始位置设置为0
u->motorfeedback .GO_motor_info [i] = getGoPoint(i);
}
u->motorfeedback .M2006 .motor =M2006;
u->motorfeedback .M3508 .motor =M3508;
u->motorfeedback .VESC_5065_M1_rpm =can ->motor .chassis5065 .as_array [0].rotor_speed ;
u->motorfeedback .VESC_5065_M2_rpm =can ->motor .chassis5065 .as_array [1].rotor_speed ;
u->motorfeedback .rotor_pit6020ecd =can ->motor .chassis6020.as_array [2].rotor_ecd ;
u->motorfeedback .rotor_pit6020rpm =can ->motor .chassis6020.as_array [2].rotor_speed ;
for(int i=0;i<4;i++){
u->motorfeedback .M3508_rpm[i] =can ->motor .motor3508 .as_array [i].rotor_speed ;
u->motorfeedback .M3508_angle [i]=can ->motor .motor3508 .as_array [i].rotor_ecd ;
}
u->cmd =c;
return 0;
}
/*上层大疆电机角度控制,使用can1的id1和2*/
int8_t UP_angle_control(UP_t *u, fp32 target_angle,MotorType_t motor) {
// 获取当前编码器角度
int8_t cnt=0;
fp32 angle ,delta;
switch(motor)
{
case M2006 :
angle = u->motorfeedback.M3508_angle[0];
if (u->motorfeedback .M2006 .init_cnt < 50) {
u->motorfeedback .M2006.orig_angle = angle; // 记录初始编码器值
u->motorfeedback .M2006.last_angle = angle;
u->motorfeedback .M2006.init_cnt++; // 初始化计数器递增
return 0;
}
delta = angle - u->motorfeedback .M2006.last_angle;
delta = angle - u->motorfeedback .M2006.last_angle;
if (delta > 4096) {
u->motorfeedback .M2006.round_cnt--; // 逆时针跨圈
} else if (delta < -4096) {
u->motorfeedback .M2006.round_cnt++; // 顺时针跨圈
}
u->motorfeedback.M2006.last_angle = angle;
// 计算总角度
float total_angle = (u->motorfeedback.M2006 .round_cnt * 8191 + (angle - u->motorfeedback.M2006.orig_angle)) * MOTOR2006_ECD_TO_ANGLE;
u->motorfeedback.M2006.total_angle =total_angle;
float delta_angle = PID_calc(&u->pid.M2006_angle, total_angle, target_angle);
float delta_speed = PID_calc(&u->pid.M2006_speed, u->motorfeedback.M3508_rpm [0], delta_angle);
u->motor_target.M2006_angle = target_angle;
u->final_out .final_3508out [0] =delta_speed;
break ;
case M3508 :
angle = u->motorfeedback.M3508_angle[1];
if (u->motorfeedback .M3508 .init_cnt < 50) {
u->motorfeedback .M3508.orig_angle = angle; // 记录初始编码器值
u->motorfeedback .M3508.last_angle = angle;
u->motorfeedback .M3508.init_cnt++; // 初始化计数器递增
return 0;
}
delta = angle - u->motorfeedback .M3508.last_angle;
delta = angle - u->motorfeedback .M3508.last_angle;
if (delta > 4096) {
u->motorfeedback .M3508.round_cnt--; // 逆时针跨圈
} else if (delta < -4096) {
u->motorfeedback .M3508.round_cnt++; // 顺时针跨圈
}
u->motorfeedback.M3508.last_angle = angle;
// 计算总角度
total_angle = (u->motorfeedback.M3508 .round_cnt * 8191 + (angle - u->motorfeedback.M3508.orig_angle)) * MOTOR2006_ECD_TO_ANGLE;
u->motorfeedback.M3508.total_angle =total_angle;
delta_angle = PID_calc(&u->pid.M3508_angle , total_angle, target_angle);
delta_speed = PID_calc(&u->pid.M3508_speed , u->motorfeedback.M3508_rpm [1], delta_angle);
u->motor_target.M3508_angle = target_angle;
u->final_out .final_3508out[1] =delta_speed;
break ;
}
return 0;
}
//int8_t UP_M3508_speed(UP_t *u,fp32 speed)
//{
// u->motor_target .M3508_speed [] =speed;
// for(int i=0;i<3;i++){
// u->final_out .final_3508out [i] =
// PID_calc (&(u->pid .M3508_speed[i] ),u->motorfeedback .M3508_speed [i],speed );
// }
//
//}
int8_t VESC_M5065_Control(UP_t *u,fp32 speed)
{
u->motor_target .VESC_5065_M1_rpm =speed;
u->motor_target .VESC_5065_M2_rpm =speed;
u->final_out .final_VESC_5065_M1out =-u->motor_target .VESC_5065_M1_rpm;
u->final_out .final_VESC_5065_M2out =u->motor_target .VESC_5065_M2_rpm;
return 0;
}
int8_t GM6020_control(UP_t *u,fp32 angle)
{
fp32 delat_speed;
// Clip(&angle,90,270);
delat_speed =
PID_calc (&(u->pid .GM6020_angle ),u->motorfeedback .rotor_pit6020ecd ,(angle /360*8191));
u->final_out .final_pitchout =
PID_calc (&(u->pid .GM6020_speed ),u->motorfeedback.rotor_pit6020rpm ,delat_speed);
u->motor_target .rotor_pit6020angle =angle ;
return 0;
}
/*go电机控制*/
int8_t GO_SendData(UP_t *u,int id,float pos)
{
fp32 deal_pos;
// deal_pos = PID_calc (&u->pid .GO1_position ,u->motorfeedback .GO_motor_info [0]->Pos ,pos);
GO_M8010_send_data(BSP_UART_GetHandle(BSP_UART_RS485), id,u->param->go_param[id] .rev ,u->param->go_param[id].T ,u->param->go_param[id] .W ,pos,u->param->go_param [id].K_P ,u->param->go_param[id] .K_W );
return 0;
}
int8_t ALL_Motor_Control(UP_t *u,CAN_Output_t *out)
{
//电机控制 传进can
UP_angle_control(u,u->motor_target .M2006_angle ,M2006);
UP_angle_control(u,u->motor_target .M3508_angle ,M3508 );
GO_SendData(u,0 ,u->motor_target .go_shoot );
for(int i=0;i<4;i++){
out ->motor3508 .as_array[i]=u->final_out.final_3508out [i] ;
}
out ->chassis5065 .erpm [0]= u->final_out .final_VESC_5065_M1out ;
out ->chassis5065 .erpm [1]= -u->final_out .final_VESC_5065_M2out ;
out ->chassis6020 .as_array [2]=u->final_out .final_pitchout ;
return 0;
}
int8_t UP_control(UP_t *u,CAN_Output_t *out,CMD_t *c)
{
if(u ==NULL) return 0;
static int is_pitch=1;
switch (c->CMD_CtrlType )
{
case UP_RCcontrol: //在手动模式下
switch (c-> CMD_UP_mode )
{
case Normal :
/*投篮*/
if(is_pitch){
u->motor_target .go_shoot =u->PitchContext .PitchConfig .go1_init_position ;
is_pitch=0;
}
u->motor_target .M2006_angle =u->PitchContext .PitchConfig .m2006_init_angle ;
u->PitchContext .PitchState = PITCH_PREPARE; //状态更新,开始夹球
// /*运球*/
// u->motor_target .go_spin = u->DribbleContext.DribbleConfig .go2_init_angle ;
// u->motor_target .M3508_angle =u->DribbleContext .DribbleConfig .m3508_init_angle ;
// u->DribbleContext .DribbleState = Dribble_PREPARE; //重置最初状态
// RELAY1_TOGGLE (1);//夹球0夹1开
// RELAY2_TOGGLE (0);//球0接1收
//
break;
case Pitch :
if (u->PitchContext .PitchState ==PITCH_PREPARE) //首次启动
{
u->PitchContext .PitchState=PITCH_START;//置标志位用于启动投篮
}
Pitch_Process(u,out,c);
break ;
case Dribble:
{
/*夹球 -> 3508 升起 同时go2翻转 -> 到位置后继电器开放球同时3508降go2翻回->接球,收 */
if(u->DribbleContext.DribbleState== Dribble_PREPARE){
u->DribbleContext .DribbleState =STATE_GRAB_BALL;
}
Dribble_Process(u,out);
}break ;
case Dribbl_transfer:
Dribbl_transfer_a(u,out);
}
break;
default:
break;
}
return 0;
}
int8_t Pitch_Process(UP_t *u, CAN_Output_t *out,CMD_t *c)
{
static fp32 go1_position,M2006_Screw_position ;
static int is_initialize=1;
if(is_initialize)
{
go1_position=u->PitchContext .PitchConfig .go1_init_position ;
M2006_Screw_position=u->PitchContext .PitchConfig .m2006_Screw_init;
is_initialize=0;
}
switch(u->PitchContext .PitchState){
case PITCH_START:
u->motor_target .go_shoot = u->PitchContext .PitchConfig .go1_release_threshold;
if(u->motorfeedback .GO_motor_info[0]->Pos < -32.40){ //检测go位置到达最上面这里的检测条件可以更改
u->motor_target .M2006_angle = u->PitchContext .PitchConfig .m2006_trigger_angle ;//设置2006角度0
u->PitchContext .PitchState=PITCH_PULL_TRIGGER;
}//更改标志位
break ;
case PITCH_PULL_TRIGGER:
if(u->motorfeedback .M2006 .total_angle >-1) //当2006的总角度小于1可以认为已经勾上,误差为1
{
u->motor_target .go_shoot = go1_position;//go下拉
u->motor_target .M3508_angle = M2006_Screw_position;//丝杠上的2006
go1_position = go1_position + c->Vx ;
M2006_Screw_position=M2006_Screw_position+ c->Vy;
}
break ;
}
return 0;
}
int8_t Dribble_Process(UP_t *u, CAN_Output_t *out)
{
switch (u->DribbleContext.DribbleState) {
case STATE_GRAB_BALL://开始
RELAY1_TOGGLE (0);//夹球
u->motor_target.M3508_angle =u->DribbleContext .DribbleConfig .m3508_high_angle;//3508升起
u->motor_target.go_spin =u->DribbleContext .DribbleConfig .go2_flip_angle;
if((u->motorfeedback .M3508 .total_angle >400)) {
RELAY2_TOGGLE (1);
if(((u->motorfeedback.GO_motor_info[1]->Pos ) <-1.1)&&(u->motorfeedback.M3508 .total_angle >1190)){
u->DribbleContext .DribbleState = STATE_RELEASE_BALL; //当go2到标准位置标志位改变
}
}
break;
case STATE_RELEASE_BALL:
RELAY1_TOGGLE (1);//松球
if((u->motorfeedback.GO_motor_info[1]->Pos ) <-1.3){
u->motor_target.go_spin =-40; //恢复go2位置
u->DribbleContext .DribbleState = STATE_CATCH_PREP; //当go2到标准位置标志位改变
}
break;
case STATE_CATCH_PREP:
if((u->motorfeedback.GO_motor_info[1]->Pos )> -0.4){
u->motor_target.M3508_angle =0 ; //当go2到初始位置3508降
RELAY2_TOGGLE (0);//接球
}
if(u->motorfeedback .M3508 .total_angle <51.0f){
RELAY1_TOGGLE (0);//夹球0夹1开
u->DribbleContext .DribbleState = STATE_TRANSFER;
}
break;
break ;
default:
break;
}
return 0;
}
void Dribbl_transfer_a(UP_t *u, CAN_Output_t *out)
{
switch (u->DribbleContext.DribbleState) {
case STATE_TRANSFER:
if((u->motorfeedback.M3508 .total_angle <52.0f )) //满足这个状态时认为go和3508到达初始位置再夹上球
{
u->motor_target .go_spin =u->DribbleContext .DribbleConfig .go2_release_threshold ;
}
if(u->motorfeedback .GO_motor_info [1]->Pos < -4.9)
{
RELAY1_TOGGLE (1);//夹球0夹1开
if(u->motorfeedback .GO_motor_info [1]->Pos > -4.8)
{
u->DribbleContext .DribbleState = STATE_CATCH_DONE; //当go2到标准位置标志位改变
}
}
break ;
case STATE_CATCH_DONE:
RELAY1_TOGGLE (1);//夹球0夹1开
RELAY2_TOGGLE (0);//夹球0接1收
u->motor_target.go_spin=u->DribbleContext .DribbleConfig.go2_init_angle ;
break;
break;
}
}