/** ****************************(C) COPYRIGHT 2021 QUT**************************** * @file motor_control.c/h * @brief 3508/2006电机初始化、速度环、位置环;6020电机初始化、位置环(相对角度) * @note 3508位置环使用的是增量式编码器,没有绝对位置,注意它所对应的角度是M3508的输出轴所对应的角度,由减速比经过换算得来, * 若要修改对于的真实角度,应该在CAN_RECEIVE中修改相对应的解码函数。 同时3508的控制函数也可对应相同ID的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; }