R2_UP/User/device/motor_control.c

250 lines
8.0 KiB
C
Raw Normal View History

2025-03-12 10:46:02 +08:00
/**
****************************(C) COPYRIGHT 2021 QUT****************************
* @file motor_control.c/h
* @brief 3508/20066020
* @note 3508使M3508的输出轴所对应的角度
* CAN_RECEIVE中修改相对应的解码函数
3508ID的2006配套使用
* @history
* Version Date Author Modification remark
* V1.0.0 Dec-23-2021 QUT 1.
* V1.0.1 Dec-23-2023 QUT hks 1.
@verbatim
==============================================================================
==============================================================================
@endverbatim
****************************(C) COPYRIGHT 2021 QUT****************************
*/
#include "motor_control.h"
#include "CAN_receive.h"
#include "pid.h"
#include "user_math.h"
#include "device\device.h"
//3508motor init ID1~4
//mode 1:velocity
// 2:pos
void M3508_motor_init(int mode);
//3508velocity_loop ID1~4
void M3508_velocity_loop(int16_t speed1,int16_t speed2,int16_t speed3,int16_t speed4);
//3508position_loop ID1~4
void M3508_pos_loop(fp32 angle1,fp32 angle2,fp32 angle3,fp32 angle4);
//6020 init ID1
void GM6020_position_loop_init(void);
//6020 pos_loop ID1 relative angle ,this is used for 6020 angel range from 0 to 180
void GM6020_pos_loop(int32_t ecd);
const motor_measure_t *motor_data[4];//3508 motor _data
pid_type_def motor_pid[4];//3508velocity_pid
pid_type_def angle_pid[4];//3508position_pid
//position_pid time interval 10ms
const fp32 speed_PID[3]={5.0,0.3,0.0}; //P,I,D(velocity)
const fp32 angle_PID[3]={25.0,0.0,1.5}; //P,I,D(position)
//velocity_pid
const fp32 PID[3]={5.0,0.01,0.0};
const motor_measure_t *GM6020_data;//6020 data_motor
gimbal_PID_t gimbal_motor_relative_angle_pid;//6020 relative angle position_pid
pid_type_def gimbal_motor_gyro_pid;//6020 relative angle velocity_pid
gimbal_pid_control_t GM6020_pos_loop_control;//6020 position_control
const fp32 GM6020_PID[3]={3600.0,20.0,0};//6020 velocity_PID
//*****3508*****//
//3508 motor init ID1~4
//mode 1:velocity
// 2:position
void M3508_motor_init(int mode)
{
//get 3508 motor_data from CAN_receive
motor_data[0] = get_chassis_motor_measure_point(0);
motor_data[1] = get_chassis_motor_measure_point(1);
motor_data[2] = get_chassis_motor_measure_point(2);
motor_data[3] = get_chassis_motor_measure_point(3);
switch(mode)
{
//velocity_init
case 1:
for(int i=0;i<4;i++)
{
PID_init(&motor_pid[i],PID_POSITION,PID,16000,2000); //velocity_pid init
}break;
//pos_init
case 2:
for(int i=0;i<4;i++)
{
PID_init(&motor_pid[i],PID_POSITION,speed_PID,16000,2000); //velocity_pid init
PID_init(&angle_pid[i],PID_POSITION,angle_PID,1000,200); // pos_pid init
}break;
}
}
//3508 velocity
/**
* @brief send control current of motor (0x201, 0x202, 0x203, 0x204)
* the param is compatable with the fab data of 3508
* @param[in] speed1: (0x201) 3508 motor control current, range [-16384,16384]
* @param[in] speed2: (0x202) 3508 motor control current, range [-16384,16384]
* @param[in] speed3: (0x203) 3508 motor control current, range [-16384,16384]
* @param[in] speed4: (0x204) 3508 motor control current, range [-16384,16384]
* @retval none
*/
void M3508_velocity_loop(int16_t speed1,int16_t speed2,int16_t speed3,int16_t speed4)
{
int32_t speed[4];
int32_t delta_speed[4];
int i;
speed[0] = speed1;
speed[1] = speed2;
speed[2] = speed3;
speed[3] = speed4;
for(i=0;i<4;i++)
{
delta_speed[i] = PID_calc(&motor_pid[i],motor_data[i]->speed_rpm,speed[i]);
}
CAN_cmd_G3508(delta_speed[0],delta_speed[1],delta_speed[2],delta_speed[3]);
}
//3508 pos
/**
* @brief send control current of motor (0x201, 0x202, 0x203, 0x204)
* this also can used to control the same ID of M2006
* the param angle is correspond to the output shaft of M3508
* @Attention!!!!! the kind fo DJI ecd is incremental.
* @param[in] angle1: (0x201) 3508 motor control current, range [reserved]
* @param[in] angle2: (0x202) 3508 motor control current, range [reserved]
* @param[in] angle3: (0x203) 3508 motor control current, range [reserved]
* @param[in] angle4: (0x204) 3508 motor control current, range [reserved]
* @retval none
*/
void M3508_pos_loop(fp32 angle1,fp32 angle2,fp32 angle3,fp32 angle4)
{
fp32 angle[4];
fp32 delta_angle[4];
int32_t delta_speed[4];
int i;
angle[0] = angle1;
angle[1] = angle2;
angle[2] = angle3;
angle[3] = angle4;
//outer ring angle_loop
for(i=0;i<4;i++)
{
delta_angle[i] = PID_calc(&angle_pid[i],motor_data[i]->total_angle,angle[i]);
}
//inner ring velocity_loop
for(i=0;i<4;i++)
{
delta_speed[i] = PID_calc(&motor_pid[i],motor_data[i]->speed_rpm,delta_angle[i]);
}
CAN_cmd_G3508(delta_speed[0],delta_speed[1],delta_speed[2],delta_speed[3]);
}
//*****6020*****//
//6020motor_init ID1
void GM6020_position_loop_init(void)
{
gimbal_PID_init(&GM6020_pos_loop_control.gimbal_motor_relative_angle_pid,10.0f,0.0f,8.0f,5.0f,0.0f); //angle_loop_pid init
PID_init(&GM6020_pos_loop_control.gimbal_motor_gyro_pid,PID_POSITION,GM6020_PID,30000.0,5000.0); //velocity_loop init
GM6020_data=get_G6020_motor_measure_point();
}
//6020Pos ID1(relative angle)
//this 6020is uesd only for angle_maximum(180)
//ecd encoder valueֵ(0-8191)
void GM6020_pos_loop(int32_t ecd)
{
//set positon
GM6020_pos_loop_control.angel_set=rad(ecd);
//calculate_relative_angle(-PI,PI)
GM6020_pos_loop_control.angel_get=motor_ecd_to_angle_change(GM6020_data->ecd,GM6020_pos_loop_control.angel_set);
//calculate_gyro (set-get)
GM6020_pos_loop_control.gyro_get=rad(GM6020_pos_loop_control.angel_set-GM6020_pos_loop_control.angel_get);
//angle_loop, pid
GM6020_pos_loop_control.gyro_set = gimbal_PID_calc(&GM6020_pos_loop_control.gimbal_motor_relative_angle_pid,GM6020_pos_loop_control.angel_get, GM6020_pos_loop_control.angel_set,GM6020_pos_loop_control.gyro_get);
GM6020_pos_loop_control.current_set = PID_calc(&GM6020_pos_loop_control.gimbal_motor_gyro_pid,GM6020_pos_loop_control.gyro_get, GM6020_pos_loop_control.gyro_set);
//control value
GM6020_pos_loop_control.current_given = (int16_t)(GM6020_pos_loop_control.current_set);
CAN_cmd_gimbal(GM6020_pos_loop_control.current_given,0,0,0);
}
void gimbal_PID_init(gimbal_PID_t *pid, fp32 maxout, fp32 max_iout, fp32 kp, fp32 ki, fp32 kd)
{
// if (pid == NULL)
// {
// return;
// }
pid->kp = kp;
pid->ki = ki;
pid->kd = kd;
pid->err = 0.0f;
pid->get = 0.0f;
pid->max_iout = max_iout;
pid->max_out = maxout;
}
fp32 gimbal_PID_calc(gimbal_PID_t *pid, fp32 get, fp32 set, fp32 error_delta)
{
fp32 err;
// if (pid == NULL)
// {
// return 0.0f;
// }
pid->get = get;
pid->set = set;
err = set - get;
pid->err = rad_format(err);
pid->Pout = pid->kp * pid->err;
pid->Iout += pid->ki * pid->err;
pid->Dout = pid->kd * error_delta;
abs_limit_fp(&pid->Iout, pid->max_iout);
pid->out = pid->Pout + pid->Iout + pid->Dout;
abs_limit_fp(&pid->out, pid->max_out);
return pid->out;
}
//calculate relative_angle (-4096,4095)
fp32 motor_ecd_to_angle_change(uint32_t ecd, uint16_t offset_ecd)
{
int32_t relative_ecd = ecd - offset_ecd;
if (relative_ecd > 4095)
{
while(relative_ecd>4095)
{
relative_ecd -= 8191;
}
}
else if (relative_ecd < -4096)
{
while(relative_ecd<-4096)
{
relative_ecd += 8191;
}
}
return relative_ecd * MOTOR_ECD_TO_RAD;
}