Files
origincar_controller/BALANCE/balance.c
2026-08-07 20:13:49 +08:00

751 lines
29 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 "balance.h"
int Time_count=0; //Time variable //计时变量
// Robot mode is wrong to detect flag bits
//机器人模式是否出错检测标志位
int robot_mode_check_flag=0;
short test_num;
Encoder OriginalEncoder; //Encoder raw data //编码器原始数据
u8 command_lost_count=0; //串口、CAN控制命令丢失时间计数丢失1秒后停止控制
/**************************************************************************
Function: The inverse kinematics solution is used to calculate the target speed of each wheel according to the target speed of three axes
Input : X and Y, Z axis direction of the target movement speed
Output : none
函数功能:运动学逆解,根据三轴目标速度计算各车轮目标转速
入口参数X和Y、Z轴方向的目标运动速度
返回 值:无
**************************************************************************/
void Drive_Motor(float Vx,float Vy,float Vz)
{
float amplitude=3.5; //Wheel target speed limit //车轮目标速度限幅
//Speed smoothing is enabled when moving the omnidirectional trolley
//全向移动小车才开启速度平滑处理
if(Car_Mode==Mec_Car||Car_Mode==Omni_Car)
{
Smooth_control(Vx,Vy,Vz); //Smoothing the input speed //对输入速度进行平滑处理
//Get the smoothed data
//获取平滑处理后的数据
Vx=smooth_control.VX;
Vy=smooth_control.VY;
Vz=smooth_control.VZ;
}
//Mecanum wheel car
//麦克纳姆轮小车
if (Car_Mode==Mec_Car)
{
//Inverse kinematics //运动学逆解
MOTOR_A.Target = +Vy+Vx-Vz*(Axle_spacing+Wheel_spacing);
MOTOR_B.Target = -Vy+Vx-Vz*(Axle_spacing+Wheel_spacing);
MOTOR_C.Target = +Vy+Vx+Vz*(Axle_spacing+Wheel_spacing);
MOTOR_D.Target = -Vy+Vx+Vz*(Axle_spacing+Wheel_spacing);
//Wheel (motor) target speed limit //车轮(电机)目标速度限幅
MOTOR_A.Target=target_limit_float(MOTOR_A.Target,-amplitude,amplitude);
MOTOR_B.Target=target_limit_float(MOTOR_B.Target,-amplitude,amplitude);
MOTOR_C.Target=target_limit_float(MOTOR_C.Target,-amplitude,amplitude);
MOTOR_D.Target=target_limit_float(MOTOR_D.Target,-amplitude,amplitude);
}
//Omni car
//全向轮小车
else if (Car_Mode==Omni_Car)
{
//Inverse kinematics //运动学逆解
MOTOR_A.Target = Vy + Omni_turn_radiaus*Vz;
MOTOR_B.Target = -X_PARAMETER*Vx - Y_PARAMETER*Vy + Omni_turn_radiaus*Vz;
MOTOR_C.Target = +X_PARAMETER*Vx - Y_PARAMETER*Vy + Omni_turn_radiaus*Vz;
//Wheel (motor) target speed limit //车轮(电机)目标速度限幅
MOTOR_A.Target=target_limit_float(MOTOR_A.Target,-amplitude,amplitude);
MOTOR_B.Target=target_limit_float(MOTOR_B.Target,-amplitude,amplitude);
MOTOR_C.Target=target_limit_float(MOTOR_C.Target,-amplitude,amplitude);
MOTOR_D.Target=0; //Out of use //没有使用到
}
//Ackermann structure car
//阿克曼小车
else if (Car_Mode==Akm_Car)
{
//Ackerman car specific related variables //阿克曼小车专用相关变量
float R, Ratio=636.56, AngleR, Angle_Servo;
// For Ackerman small car, Vz represents the front wheel steering Angle
//对于阿克曼小车Vz代表右前轮转向角度
AngleR=Vz;
R=Axle_spacing/tan(AngleR)-0.5f*Wheel_spacing;
//R=Axle_spacing/tan(AngleR);
// Front wheel steering Angle limit (front wheel steering Angle controlled by steering engine), unit: rad
//前轮转向角度限幅(舵机控制前轮转向角度)单位rad
AngleR=target_limit_float(AngleR,-0.6f,0.6f);
//Inverse kinematics //运动学逆解
if(AngleR!=0)
{
MOTOR_A.Target = Vx*(R-0.5f*Wheel_spacing)/R;
MOTOR_B.Target = Vx*(R+0.5f*Wheel_spacing)/R;
}
else
{
MOTOR_A.Target = Vx;
MOTOR_B.Target = Vx;
}
// The PWM value of the servo controls the steering Angle of the front wheel
//舵机PWM值舵机控制前轮转向角度
Angle_Servo = -0.628f*pow(AngleR, 3) + 1.269f*pow(AngleR, 2) - 1.772f*AngleR + 1.573f;
Servo=SERVO_INIT + (Angle_Servo - 1.572f)*Ratio;
// Servo=SERVO_INIT + (Angle_Servo)*Ratio;
//Wheel (motor) target speed limit //车轮(电机)目标速度限幅
MOTOR_A.Target=target_limit_float(MOTOR_A.Target,-amplitude,amplitude);
MOTOR_B.Target=target_limit_float(MOTOR_B.Target,-amplitude,amplitude);
MOTOR_C.Target=0; //Out of use //没有使用到
MOTOR_D.Target=0; //Out of use //没有使用到
Servo=target_limit_int(Servo,800,2200); //Servo PWM value limit //舵机PWM值限幅
}
//Differential car
//差速小车
else if (Car_Mode==Diff_Car)
{
//Inverse kinematics //运动学逆解
MOTOR_A.Target = Vx - Vz * Wheel_spacing / 2.0f; //计算出左轮的目标速度
MOTOR_B.Target = Vx + Vz * Wheel_spacing / 2.0f; //计算出右轮的目标速度
//Wheel (motor) target speed limit //车轮(电机)目标速度限幅
MOTOR_A.Target=target_limit_float( MOTOR_A.Target,-amplitude,amplitude);
MOTOR_B.Target=target_limit_float( MOTOR_B.Target,-amplitude,amplitude);
MOTOR_C.Target=0; //Out of use //没有使用到
MOTOR_D.Target=0; //Out of use //没有使用到
}
//FourWheel car
//四驱车
else if(Car_Mode==FourWheel_Car)
{
//Inverse kinematics //运动学逆解
MOTOR_A.Target = Vx - Vz * (Wheel_spacing + Axle_spacing) / 2.0f; //计算出左轮的目标速度
MOTOR_B.Target = Vx - Vz * (Wheel_spacing + Axle_spacing) / 2.0f; //计算出左轮的目标速度
MOTOR_C.Target = Vx + Vz * (Wheel_spacing + Axle_spacing) / 2.0f; //计算出右轮的目标速度
MOTOR_D.Target = Vx + Vz * (Wheel_spacing + Axle_spacing) / 2.0f; //计算出右轮的目标速度
//Wheel (motor) target speed limit //车轮(电机)目标速度限幅
MOTOR_A.Target=target_limit_float( MOTOR_A.Target,-amplitude,amplitude);
MOTOR_B.Target=target_limit_float( MOTOR_B.Target,-amplitude,amplitude);
MOTOR_C.Target=target_limit_float( MOTOR_C.Target,-amplitude,amplitude);
MOTOR_D.Target=target_limit_float( MOTOR_D.Target,-amplitude,amplitude);
}
//Tank Car
//履带车
else if (Car_Mode==Tank_Car)
{
//Inverse kinematics //运动学逆解
MOTOR_A.Target = Vx - Vz * (Wheel_spacing) / 2.0f; //计算出左轮的目标速度
MOTOR_B.Target = Vx + Vz * (Wheel_spacing) / 2.0f; //计算出右轮的目标速度
//Wheel (motor) target speed limit //车轮(电机)目标速度限幅
MOTOR_A.Target=target_limit_float( MOTOR_A.Target,-amplitude,amplitude);
MOTOR_B.Target=target_limit_float( MOTOR_B.Target,-amplitude,amplitude);
MOTOR_C.Target=0; //Out of use //没有使用到
MOTOR_D.Target=0; //Out of use //没有使用到
}
}
/**************************************************************************
Function: FreerTOS task, core motion control task
Input : none
Output : none
函数功能FreeRTOS任务核心运动控制任务
入口参数:无
返回 值:无
**************************************************************************/
void Balance_task(void *pvParameters)
{
u32 lastWakeTime = getSysTickCnt();
while(1)
{
// This task runs at a frequency of 100Hz (10ms control once)
//此任务以100Hz的频率运行10ms控制一次
vTaskDelayUntil(&lastWakeTime, F2T(RATE_100_HZ));
//Time count is no longer needed after 30 seconds
//时间计数30秒后不再需要
if(Time_count<3000)Time_count++;
//Get the encoder data, that is, the real time wheel speed,
//and convert to transposition international units
//获取编码器数据,即车轮实时速度,并转换位国际单位
Get_Velocity_Form_Encoder();
if(Check==0) //If self-check mode is not enabled //如果没有启动自检模式
{
// command_lost_count++; //串口、CAN控制命令丢失时间计数丢失1秒后停止控制
// if(command_lost_count>RATE_100_HZ && APP_ON_Flag==0 && Remote_ON_Flag==0 && PS2_ON_Flag==0) //不是APP、PS2、航模遥控模式就是CAN、串口1、串口3控制模式
// Move_X=0, Move_Y=0, Move_Z=0;
if (APP_ON_Flag) Get_RC(); //Handle the APP remote commands //处理APP遥控命令
else if (Remote_ON_Flag) Remote_Control(); //Handle model aircraft remote commands //处理航模遥控命令
else if (PS2_ON_Flag) PS2_control(); //Handle PS2 controller commands //处理PS2手柄控制命令
//CAN, Usart 1, Usart 3, Uart5 control can directly get the three axis target speed,
//without additional processing
//CAN、串口1、串口3(ROS)、串口5控制直接得到三轴目标速度无须额外处理
else Drive_Motor(Move_X, Move_Y, Move_Z);
//Click the user button to update the gyroscope zero
//单击用户按键更新陀螺仪零点
Key();
//If there is no abnormity in the battery voltage, and the enable switch is in the ON position,
//and the software failure flag is 0
//如果电池电压不存在异常而且使能开关在ON档位而且软件失能标志位为0
if(Turn_Off(Voltage)==0)
{
//Speed closed-loop control to calculate the PWM value of each motor,
//PWM represents the actual wheel speed
//速度闭环控制计算各电机PWM值PWM代表车轮实际转速
MOTOR_A.Motor_Pwm=Incremental_PI_A(MOTOR_A.Encoder, MOTOR_A.Target);
MOTOR_B.Motor_Pwm=Incremental_PI_B(MOTOR_B.Encoder, MOTOR_B.Target);
MOTOR_C.Motor_Pwm=Incremental_PI_C(MOTOR_C.Encoder, MOTOR_C.Target);
MOTOR_D.Motor_Pwm=Incremental_PI_D(MOTOR_D.Encoder, MOTOR_D.Target);
Limit_Pwm(16700);
//Set different PWM control polarity according to different car models
//根据不同小车型号设置不同的PWM控制极性
switch(Car_Mode)
{
case Mec_Car: Set_Pwm( MOTOR_A.Motor_Pwm, -MOTOR_B.Motor_Pwm, -MOTOR_C.Motor_Pwm, MOTOR_D.Motor_Pwm, 0 ); break; //Mecanum wheel car //麦克纳姆轮小车
case Omni_Car: Set_Pwm(-MOTOR_A.Motor_Pwm, MOTOR_B.Motor_Pwm, -MOTOR_C.Motor_Pwm, MOTOR_D.Motor_Pwm, 0 ); break; //Omni car //全向轮小车
case Akm_Car: Set_Pwm( MOTOR_A.Motor_Pwm, MOTOR_B.Motor_Pwm, 16799,-16799 , Servo); break; //Ackermann structure car //阿克曼小车
case Diff_Car: Set_Pwm( MOTOR_A.Motor_Pwm, MOTOR_B.Motor_Pwm, MOTOR_C.Motor_Pwm, MOTOR_D.Motor_Pwm, 0 ); break; //Differential car //两轮差速小车
case FourWheel_Car: Set_Pwm( MOTOR_A.Motor_Pwm, -MOTOR_B.Motor_Pwm, -MOTOR_C.Motor_Pwm, MOTOR_D.Motor_Pwm, 0 ); break; //FourWheel car //四驱车
case Tank_Car: Set_Pwm( MOTOR_A.Motor_Pwm, MOTOR_B.Motor_Pwm, MOTOR_C.Motor_Pwm, MOTOR_D.Motor_Pwm, 0 ); break; //Tank Car //履带车
}
}
//If Turn_Off(Voltage) returns to 1, the car is not allowed to move, and the PWM value is set to 0
//如果Turn_Off(Voltage)返回值为1不允许控制小车进行运动PWM值设置为0
else Set_Pwm(0,0,0,0,(Car_Mode == Akm_Car) ? SERVO_INIT : 0);
}
}
}
/**************************************************************************
Function: Assign a value to the PWM register to control wheel speed and direction
Input : PWM
Output : none
函数功能赋值给PWM寄存器控制车轮转速与方向
入口参数PWM
返回 值:无
**************************************************************************/
void Set_Pwm(int motor_a,int motor_b,int motor_c,int motor_d,int servo)
{
//Forward and reverse control of motor
//电机正反转控制
if(motor_a<0) PWMA1=16799,PWMA2=16799+motor_a;
else PWMA2=16799,PWMA1=16799-motor_a;
//Forward and reverse control of motor
//电机正反转控制
if(motor_b<0) PWMB1=16799,PWMB2=16799+motor_b;
else PWMB2=16799,PWMB1=16799-motor_b;
// PWMB1=10000,PWMB2=5000;
//Forward and reverse control of motor
//电机正反转控制
if(motor_c<0) PWMC1=16799,PWMC2=16799+motor_c;
else PWMC2=16799,PWMC1=16799-motor_c;
//Forward and reverse control of motor
//电机正反转控制
if(motor_d<0) PWMD1=16799,PWMD2=16799+motor_d;
else PWMD2=16799,PWMD1=16799-motor_d;
//Servo control
//舵机控制
Servo_PWM =servo;
}
/**************************************************************************
Function: Limit PWM value
Input : Value
Output : none
函数功能限制PWM值
入口参数:幅值
返回 值:无
**************************************************************************/
void Limit_Pwm(int amplitude)
{
MOTOR_A.Motor_Pwm=target_limit_float(MOTOR_A.Motor_Pwm,-amplitude,amplitude);
MOTOR_B.Motor_Pwm=target_limit_float(MOTOR_B.Motor_Pwm,-amplitude,amplitude);
MOTOR_C.Motor_Pwm=target_limit_float(MOTOR_C.Motor_Pwm,-amplitude,amplitude);
MOTOR_D.Motor_Pwm=target_limit_float(MOTOR_D.Motor_Pwm,-amplitude,amplitude);
}
/**************************************************************************
Function: Limiting function
Input : Value
Output : none
函数功能:限幅函数
入口参数:幅值
返回 值:无
**************************************************************************/
float target_limit_float(float insert,float low,float high)
{
if (insert < low)
return low;
else if (insert > high)
return high;
else
return insert;
}
int target_limit_int(int insert,int low,int high)
{
if (insert < low)
return low;
else if (insert > high)
return high;
else
return insert;
}
/**************************************************************************
Function: Check the battery voltage, enable switch status, software failure flag status
Input : Voltage
Output : Whether control is allowed, 1: not allowed, 0 allowed
函数功能:检查电池电压、使能开关状态、软件失能标志位状态
入口参数:电压
返回 值是否允许控制1不允许0允许
**************************************************************************/
u8 Turn_Off( int voltage)
{
u8 temp;
if(voltage<10||EN==0||Flag_Stop==1)
{
temp=1;
PWMA1=0;PWMA2=0;
PWMB1=0;PWMB2=0;
PWMC1=0;PWMC1=0;
PWMD1=0;PWMD2=0;
}
else
temp=0;
return temp;
}
/**************************************************************************
Function: Calculate absolute value
Input : long int
Output : unsigned int
函数功能:求绝对值
入口参数long int
返回 值unsigned int
**************************************************************************/
u32 myabs(long int a)
{
u32 temp;
if(a<0) temp=-a;
else temp=a;
return temp;
}
/**************************************************************************
Function: Incremental PI controller
Input : Encoder measured value (actual speed), target speed
Output : Motor PWM
According to the incremental discrete PID formula
pwm+=Kp[ek-e(k-1)]+Ki*e(k)+Kd[e(k)-2e(k-1)+e(k-2)]
e(k) represents the current deviation
e(k-1) is the last deviation and so on
PWM stands for incremental output
In our speed control closed loop system, only PI control is used
pwm+=Kp[ek-e(k-1)]+Ki*e(k)
函数功能增量式PI控制器
入口参数:编码器测量值(实际速度),目标速度
返回 值电机PWM
根据增量式离散PID公式
pwm+=Kp[ek-e(k-1)]+Ki*e(k)+Kd[e(k)-2e(k-1)+e(k-2)]
e(k)代表本次偏差
e(k-1)代表上一次的偏差 以此类推
pwm代表增量输出
在我们的速度控制闭环系统里面只使用PI控制
pwm+=Kp[ek-e(k-1)]+Ki*e(k)
**************************************************************************/
int Incremental_PI_A (float Encoder,float Target)
{
static float Bias,Pwm,Last_bias;
Bias=Target-Encoder; //Calculate the deviation //计算偏差
Pwm+=Velocity_KP*(Bias-Last_bias)+Velocity_KI*Bias;
if(Pwm>16700)Pwm=16700;
if(Pwm<-16700)Pwm=-16700;
Last_bias=Bias; //Save the last deviation //保存上一次偏差
return Pwm;
}
int Incremental_PI_B (float Encoder,float Target)
{
static float Bias,Pwm,Last_bias;
Bias=Target-Encoder; //Calculate the deviation //计算偏差
Pwm+=Velocity_KP*(Bias-Last_bias)+Velocity_KI*Bias;
if(Pwm>16700)Pwm=16700;
if(Pwm<-16700)Pwm=-16700;
Last_bias=Bias; //Save the last deviation //保存上一次偏差
return Pwm;
}
int Incremental_PI_C (float Encoder,float Target)
{
static float Bias,Pwm,Last_bias;
Bias=Target-Encoder; //Calculate the deviation //计算偏差
Pwm+=Velocity_KP*(Bias-Last_bias)+Velocity_KI*Bias;
if(Pwm>16700)Pwm=16700;
if(Pwm<-16700)Pwm=-16700;
Last_bias=Bias; //Save the last deviation //保存上一次偏差
return Pwm;
}
int Incremental_PI_D (float Encoder,float Target)
{
static float Bias,Pwm,Last_bias;
Bias=Target-Encoder; //Calculate the deviation //计算偏差
Pwm+=Velocity_KP*(Bias-Last_bias)+Velocity_KI*Bias;
if(Pwm>16700)Pwm=16700;
if(Pwm<-16700)Pwm=-16700;
Last_bias=Bias; //Save the last deviation //保存上一次偏差
return Pwm;
}
/**************************************************************************
Function: Processes the command sent by APP through usart 2
Input : none
Output : none
函数功能对APP通过串口2发送过来的命令进行处理
入口参数:无
返回 值:无
**************************************************************************/
void Get_RC(void)
{
u8 Flag_Move=1;
if(Car_Mode==Mec_Car||Car_Mode==Omni_Car) //The omnidirectional wheel moving trolley can move laterally //全向轮运动小车可以进行横向移动
{
switch(Flag_Direction) //Handle direction control commands //处理方向控制命令
{
case 1: Move_X=RC_Velocity; Move_Y=0; Flag_Move=1; break;
case 2: Move_X=RC_Velocity; Move_Y=-RC_Velocity; Flag_Move=1; break;
case 3: Move_X=0; Move_Y=-RC_Velocity; Flag_Move=1; break;
case 4: Move_X=-RC_Velocity; Move_Y=-RC_Velocity; Flag_Move=1; break;
case 5: Move_X=-RC_Velocity; Move_Y=0; Flag_Move=1; break;
case 6: Move_X=-RC_Velocity; Move_Y=RC_Velocity; Flag_Move=1; break;
case 7: Move_X=0; Move_Y=RC_Velocity; Flag_Move=1; break;
case 8: Move_X=RC_Velocity; Move_Y=RC_Velocity; Flag_Move=1; break;
default: Move_X=0; Move_Y=0; Flag_Move=0; break;
}
if(Flag_Move==0)
{
//If no direction control instruction is available, check the steering control status
//如果无方向控制指令,检查转向控制状态
if (Flag_Left ==1) Move_Z= PI/2*(RC_Velocity/500); //left rotation //左自转
else if(Flag_Right==1) Move_Z=-PI/2*(RC_Velocity/500); //right rotation //右自转
else Move_Z=0; //stop //停止
}
}
else //Non-omnidirectional moving trolley //非全向移动小车
{
switch(Flag_Direction) //Handle direction control commands //处理方向控制命令
{
case 1: Move_X=+RC_Velocity; Move_Z=0; break;
case 2: Move_X=+RC_Velocity; Move_Z=-PI/2; break;
case 3: Move_X=0; Move_Z=-PI/2; break;
case 4: Move_X=-RC_Velocity; Move_Z=-PI/2; break;
case 5: Move_X=-RC_Velocity; Move_Z=0; break;
case 6: Move_X=-RC_Velocity; Move_Z=+PI/2; break;
case 7: Move_X=0; Move_Z=+PI/2; break;
case 8: Move_X=+RC_Velocity; Move_Z=+PI/2; break;
default: Move_X=0; Move_Z=0; break;
}
if (Flag_Left ==1) Move_Z= PI/2; //left rotation //左自转
else if(Flag_Right==1) Move_Z=-PI/2; //right rotation //右自转
}
//Z-axis data conversion //Z轴数据转化
if(Car_Mode==Akm_Car)
{
//Ackermann structure car is converted to the front wheel steering Angle system target value, and kinematics analysis is pearformed
//阿克曼结构小车转换为前轮转向角度
Move_Z=Move_Z*2/9;
}
else if(Car_Mode==Diff_Car||Car_Mode==Tank_Car||Car_Mode==FourWheel_Car)
{
if(Move_X<0) Move_Z=-Move_Z; //The differential control principle series requires this treatment //差速控制原理系列需要此处理
Move_Z=Move_Z*RC_Velocity/500;
}
//Unit conversion, mm/s -> m/s
//单位转换mm/s -> m/s
Move_X=Move_X/1000; Move_Y=Move_Y/1000; Move_Z=Move_Z;
//Control target value is obtained and kinematics analysis is performed
//得到控制目标值,进行运动学分析
Drive_Motor(Move_X,Move_Y,Move_Z);
}
/**************************************************************************
Function: Handle PS2 controller control commands
Input : none
Output : none
函数功能对PS2手柄控制命令进行处理
入口参数:无
返回 值:无
**************************************************************************/
void PS2_control(void)
{
int LX,LY,RY;
int Threshold=20; //Threshold to ignore small movements of the joystick //阈值,忽略摇杆小幅度动作
//128 is the median.The definition of X and Y in the PS2 coordinate system is different from that in the ROS coordinate system
//128为中值。PS2坐标系与ROS坐标系对X、Y的定义不一样
LY=-(PS2_LX-128);
LX=-(PS2_LY-128);
RY=-(PS2_RX-128);
//Ignore small movements of the joystick //忽略摇杆小幅度动作
if(LX>-Threshold&&LX<Threshold)LX=0;
if(LY>-Threshold&&LY<Threshold)LY=0;
if(RY>-Threshold&&RY<Threshold)RY=0;
if (PS2_KEY==11) RC_Velocity+=5; //To accelerate//加速
else if(PS2_KEY==9) RC_Velocity-=5; //To slow down //减速
if(RC_Velocity<0) RC_Velocity=0;
//Handle PS2 controller control commands
//对PS2手柄控制命令进行处理
Move_X=LX*RC_Velocity/128;
Move_Y=LY*RC_Velocity/128;
Move_Z=RY*(PI/2)/128;
//Z-axis data conversion //Z轴数据转化
if(Car_Mode==Mec_Car||Car_Mode==Omni_Car)
{
Move_Z=Move_Z*RC_Velocity/500;
}
else if(Car_Mode==Akm_Car)
{
//Ackermann structure car is converted to the front wheel steering Angle system target value, and kinematics analysis is pearformed
//阿克曼结构小车转换为前轮转向角度
Move_Z=Move_Z*2/9;
}
else if(Car_Mode==Diff_Car||Car_Mode==Tank_Car||Car_Mode==FourWheel_Car)
{
if(Move_X<0) Move_Z=-Move_Z; //The differential control principle series requires this treatment //差速控制原理系列需要此处理
Move_Z=Move_Z*RC_Velocity/500;
}
//Unit conversion, mm/s -> m/s
//单位转换mm/s -> m/s
Move_X=Move_X/1000;
Move_Y=Move_Y/1000;
Move_Z=Move_Z;
//Control target value is obtained and kinematics analysis is performed
//得到控制目标值,进行运动学分析
Drive_Motor(Move_X,Move_Y,Move_Z);
}
/**************************************************************************
Function: The remote control command of model aircraft is processed
Input : none
Output : none
函数功能:对航模遥控控制命令进行处理
入口参数:无
返回 值:无
**************************************************************************/
void Remote_Control(void)
{
//Data within 1 second after entering the model control mode will not be processed
//对进入航模控制模式后1秒内的数据不处理
static u8 thrice=100;
int Threshold=100; //Threshold to ignore small movements of the joystick //阈值,忽略摇杆小幅度动作
//limiter //限幅
int LX,LY,RY,RX,Remote_RCvelocity;
Remoter_Ch1=target_limit_int(Remoter_Ch1,1000,2000);
Remoter_Ch2=target_limit_int(Remoter_Ch2,1000,2000);
Remoter_Ch3=target_limit_int(Remoter_Ch3,1000,2000);
Remoter_Ch4=target_limit_int(Remoter_Ch4,1000,2000);
// Front and back direction of left rocker. Control forward and backward.
//左摇杆前后方向。控制前进后退。
LX=Remoter_Ch2-1500;
//Left joystick left and right.Control left and right movement. Only the wheelie omnidirectional wheelie will use the channel.
//Ackerman trolleys use this channel as a PWM output to control the steering gear
//左摇杆左右方向。控制左右移动。麦轮全向轮才会使用到改通道。阿克曼小车使用该通道作为PWM输出控制舵机
LY=Remoter_Ch4-1500;
//Front and back direction of right rocker. Throttle/acceleration/deceleration.
//右摇杆前后方向。油门/加减速。
RX=Remoter_Ch3-1500;
//Right stick left and right. To control the rotation.
//右摇杆左右方向。控制自转。
RY=Remoter_Ch1-1500;
if(LX>-Threshold&&LX<Threshold)LX=0;
if(LY>-Threshold&&LY<Threshold)LY=0;
if(RX>-Threshold&&RX<Threshold)RX=0;
if(RY>-Threshold&&RY<Threshold)RY=0;
//Throttle related //油门相关
Remote_RCvelocity=RC_Velocity+RX;
if(Remote_RCvelocity<0)Remote_RCvelocity=0;
//The remote control command of model aircraft is processed
//对航模遥控控制命令进行处理
Move_X= LX*Remote_RCvelocity/500;
Move_Y=-LY*Remote_RCvelocity/500;
Move_Z=-RY*(PI/2)/500;
//Z轴数据转化
if(Car_Mode==Mec_Car||Car_Mode==Omni_Car)
{
Move_Z=Move_Z*Remote_RCvelocity/500;
}
else if(Car_Mode==Akm_Car)
{
//Ackermann structure car is converted to the front wheel steering Angle system target value, and kinematics analysis is pearformed
//阿克曼结构小车转换为前轮转向角度
Move_Z=Move_Z*2/9;
}
else if(Car_Mode==Diff_Car||Car_Mode==Tank_Car||Car_Mode==FourWheel_Car)
{
if(Move_X<0) Move_Z=-Move_Z; //The differential control principle series requires this treatment //差速控制原理系列需要此处理
Move_Z=Move_Z*Remote_RCvelocity/500;
}
//Unit conversion, mm/s -> m/s
//单位转换mm/s -> m/s
Move_X=Move_X/1000;
Move_Y=Move_Y/1000;
Move_Z=Move_Z;
//Data within 1 second after entering the model control mode will not be processed
//对进入航模控制模式后1秒内的数据不处理
if(thrice>0) Move_X=0,Move_Z=0,thrice--;
//Control target value is obtained and kinematics analysis is performed
//得到控制目标值,进行运动学分析
Drive_Motor(Move_X,Move_Y,Move_Z);
}
/**************************************************************************
Function: Click the user button to update gyroscope zero
Input : none
Output : none
函数功能:单击用户按键更新陀螺仪零点
入口参数:无
返回 值:无
**************************************************************************/
void Key(void)
{
u8 tmp;
tmp=click_N_Double_MPU6050(50);
if(tmp==2)memcpy(Deviation_gyro,Original_gyro,sizeof(gyro)),memcpy(Deviation_accel,Original_accel,sizeof(accel));
}
/**************************************************************************
Function: Read the encoder value and calculate the wheel speed, unit m/s
Input : none
Output : none
函数功能读取编码器数值并计算车轮速度单位m/s
入口参数:无
返回 值:无
**************************************************************************/
void Get_Velocity_Form_Encoder(void)
{
//Retrieves the original data of the encoder
//获取编码器的原始数据
float Encoder_A_pr,Encoder_B_pr,Encoder_C_pr,Encoder_D_pr;
OriginalEncoder.A=Read_Encoder(2);
OriginalEncoder.B=Read_Encoder(3);
OriginalEncoder.C=Read_Encoder(4);
OriginalEncoder.D=Read_Encoder(5);
//test_num=OriginalEncoder.B;
//Decide the encoder numerical polarity according to different car models
//根据不同小车型号决定编码器数值极性
switch(Car_Mode)
{
case Mec_Car: Encoder_A_pr= OriginalEncoder.A; Encoder_B_pr= OriginalEncoder.B; Encoder_C_pr=-OriginalEncoder.C; Encoder_D_pr=-OriginalEncoder.D; break;
case Omni_Car: Encoder_A_pr=-OriginalEncoder.A; Encoder_B_pr=-OriginalEncoder.B; Encoder_C_pr=-OriginalEncoder.C; Encoder_D_pr=-OriginalEncoder.D; break;
case Akm_Car: Encoder_A_pr= OriginalEncoder.A; Encoder_B_pr=-OriginalEncoder.B; Encoder_C_pr= OriginalEncoder.C; Encoder_D_pr= OriginalEncoder.D; break;
case Diff_Car: Encoder_A_pr= OriginalEncoder.A; Encoder_B_pr=-OriginalEncoder.B; Encoder_C_pr= OriginalEncoder.C; Encoder_D_pr= OriginalEncoder.D; break;
case FourWheel_Car: Encoder_A_pr= OriginalEncoder.A; Encoder_B_pr= OriginalEncoder.B; Encoder_C_pr=-OriginalEncoder.C; Encoder_D_pr=-OriginalEncoder.D; break;
case Tank_Car: Encoder_A_pr= OriginalEncoder.A; Encoder_B_pr=-OriginalEncoder.B; Encoder_C_pr= OriginalEncoder.C; Encoder_D_pr= OriginalEncoder.D; break;
}
//The encoder converts the raw data to wheel speed in m/s
//编码器原始数据转换为车轮速度单位m/s
MOTOR_A.Encoder= Encoder_A_pr*CONTROL_FREQUENCY*Wheel_perimeter/Encoder_precision;
MOTOR_B.Encoder= Encoder_B_pr*CONTROL_FREQUENCY*Wheel_perimeter/Encoder_precision;
MOTOR_C.Encoder= Encoder_C_pr*CONTROL_FREQUENCY*Wheel_perimeter/Encoder_precision;
MOTOR_D.Encoder= Encoder_D_pr*CONTROL_FREQUENCY*Wheel_perimeter/Encoder_precision;
}
/**************************************************************************
Function: Smoothing the three axis target velocity
Input : Three-axis target velocity
Output : none
函数功能:对三轴目标速度做平滑处理
入口参数:三轴目标速度
返回 值:无
**************************************************************************/
void Smooth_control(float vx,float vy,float vz)
{
float step=0.01;
if (vx>0) smooth_control.VX+=step;
else if(vx<0) smooth_control.VX-=step;
else if(vx==0) smooth_control.VX=smooth_control.VX*0.9f;
if (vy>0) smooth_control.VY+=step;
else if(vy<0) smooth_control.VY-=step;
else if(vy==0) smooth_control.VY=smooth_control.VY*0.9f;
if (vz>0) smooth_control.VZ+=step;
else if(vz<0) smooth_control.VZ-=step;
else if(vz==0) smooth_control.VZ=smooth_control.VZ*0.9f;
smooth_control.VX=target_limit_float(smooth_control.VX,-float_abs(vx),float_abs(vx));
smooth_control.VY=target_limit_float(smooth_control.VY,-float_abs(vy),float_abs(vy));
smooth_control.VZ=target_limit_float(smooth_control.VZ,-float_abs(vz),float_abs(vz));
}
/**************************************************************************
Function: Floating-point data calculates the absolute value
Input : float
Output : The absolute value of the input number
函数功能:浮点型数据计算绝对值
入口参数:浮点数
返回 值:输入数的绝对值
**************************************************************************/
float float_abs(float insert)
{
if(insert>=0) return insert;
else return -insert;
}
/**************************************************************************
Function: Prevent the potentiometer to choose the wrong mode, resulting in initialization error caused by the motor spinning.Out of service
Input : none
Output : none
函数功能:防止电位器选错模式,导致初始化出错引发电机乱转。已停止使用
入口参数:无
返回 值:无
**************************************************************************/
void robot_mode_check(void)
{
static u8 error=0;
if(abs(MOTOR_A.Motor_Pwm)>2500||abs(MOTOR_B.Motor_Pwm)>2500||abs(MOTOR_C.Motor_Pwm)>2500||abs(MOTOR_D.Motor_Pwm)>2500) error++;
//If the output is close to full amplitude for 6 times in a row, it is judged that the motor rotates wildly and makes the motor incapacitated
//如果连续6次接近满幅输出判断为电机乱转让电机失能
if(error>6) EN=0,Flag_Stop=1,robot_mode_check_flag=1;
}