1.前言
最近参加ROBOCON,我负责编写传球机器人,由于传球机构需要一个电机转固定角度来带动球,所以便用大疆3508电机通过串级PID来实现,不得不说3508电机还是真的强,先看一下效果吧。
视频
2.配置程序
关于3508的配置程序以及一些其他部分在我的另外一篇博客里有详细的介绍,本篇主要是详细讲解3508串级pid(转固定角度)。
大疆3508/2006/6020电机使用教程
3.角度位置控制
3508电机的串级PID控制比起其他直流电机要简单一些,不需要过多的处理编码盘的反馈,只需要读取电调反馈的角度。
关于串级PID的知识,csdn上有很多,我就不赘述了。
直流电机角度位置控制详解(附源码)
直流电机角度控制
3.1 先看一下电调反馈的数据
if((rx_message.StdId == (MOTOR_ID_READ+5)) ) //电机5
{
MOTOR_FEEDBACK[5].angle_value = rx_message.Data[0] << 8 | rx_message.Data[1];
MOTOR_FEEDBACK[5].speed_rpm = rx_message.Data[2] << 8 | rx_message.Data[3];
MOTOR_FEEDBACK[5].real_current = rx_message.Data[4] << 8 | rx_message.Data[5];
MOTOR_FEEDBACK[5].temperature = rx_message.Data[6];
MOTOR_FEEDBACK[5].real_angle = MOTOR_FEEDBACK[5].angle_value/8192.0f*360.0f;
}
这里电调ID要对应上,否则回接受不到数据,另外我们主要用的反馈是real.angle这个数据。
3.2角度处理程序
先说一下这个入口参数motor_num是电调ID,T是一个周期的角度值(自设360),通过这个函数可以得到电机的绝对角度POS_ABS。
u8 cnt = 1;
void Motor_Angle_Cal(unsigned short int motor_num,float T)
{
float res1, res2;
// int res3, res4;
static float pos[MOTOR_MAX], pos_old[MOTOR_MAX];
if(flag.cnt_calib&&cnt)
{
pos_old[motor_num]=MOTOR_FEEDBACK[motor_num].real_angle;
cnt=0;
}
pos[motor_num] =MOTOR_FEEDBACK[motor_num].real_angle;
motor.ANGLE[motor_num].eer=pos[motor_num] - pos_old[motor_num];
if(motor.ANGLE[motor_num].eer>0)
{
res1=motor.ANGLE[motor_num].eer-T;//反转,自减
res2=motor.ANGLE[motor_num].eer;
}
else
{
res1=motor.ANGLE[motor_num].eer+T;//正转,自加一个周期的角度值(360)
res2=motor.ANGLE[motor_num].eer;
}
if(ABS(res1)<ABS(res2)) //不管正反转,肯定是转的角度小的那个是真的
{
motor.ANGLE[motor_num].eer_eer = res1;
}
else
{
motor.ANGLE[motor_num].eer_eer = res2;
}
motor.ANGLE[motor_num].POS_ABS += motor.ANGLE[motor_num].eer_eer;
pos_old[motor_num] = pos[motor_num];
}
//一些角度控制的结构体变量
typedef struct
{
float POS_GAOL;//目标位置
float POS_ABS;//绝对位置0
float POS_OFFSET;
float eer;
float eer_eer;
}ANGLE_TypeDef;
typedef struct
{
ANGLE_TypeDef ANGLE[8];
_PID PID_SPEED[8];
_PID PID_ANGLE[8];
}MOTOR_TypeDef;
3.3 主要程序
//PID
float PID_Cal_Limt(_PID *PID, float limit, float get, float set)//PID死区修改
{
PID->err = set - get;
PID->err_err = PID->err - PID->err_old;
PID->P_OUT = PID->P * PID->err;
PID->I_OUT += PID->I * PID->err;
PID->D_OUT = PID->D * PID->err_err;
PID->I_OUT = (PID->I_OUT > PID->I_LIMIT)?(PID->I_LIMIT):((PID->I_OUT < -PID->I_LIMIT)?(-PID->I_LIMIT):(PID->I_OUT));
PID->OUT = PID->P_OUT + PID->I_OUT + PID->D_OUT;
PID->OUT = (PID->OUT > PID->OUT_LIMIT)?(PID->OUT_LIMIT):((PID->OUT < -PID->OUT_LIMIT)?(-PID->OUT_LIMIT):(PID->OUT));
if(ABS(PID->err) <= ABS(limit))
{
PID->I_OUT=0;
PID->OUT=0;
}
PID->err_old = PID->err;
return PID->OUT;
}
float motor_err[10]; //死区控制
float mode=0; //mode0-发射;mode1-回收
float angle_a=0,angle_b=0;//a-发射角度;b-回收角度
void Motor_Auto_Run(void)
{
motor_err[5]=50;
float abs_err[10];
static float abs_err_old[10];
Motor_Angle_Cal(5,360);//得到绝对角度
//发射
if(mode == 0)
{
motor.ANGLE[5].POS_GAOL = angle_a;
PID_Cal_Limt(&motor.PID_ANGLE[5], motor_err[5], motor.ANGLE[5].POS_ABS,motor.ANGLE[5].POS_GAOL);
abs_err[5] = motor.ANGLE[5].POS_ABS - abs_err_old[5];
PID_Cal_Limt( &motor.PID_SPEED[5], 10, abs_err[5], motor.PID_ANGLE[5].OUT);
abs_err_old[5] = motor.ANGLE[5].POS_ABS;
Motor_Set_Current2((int16_t)(motor.PID_SPEED[5].OUT) ,0,0,0);
}
//回
else if (mode == 1)
{
motor.ANGLE[5].POS_GAOL = angle_b ;
PID_Cal_Limt(&motor.PID_ANGLE[6], motor_err[5], motor.ANGLE[5].POS_ABS,motor.ANGLE[5].POS_GAOL);
abs_err[5] = motor.ANGLE[5].POS_ABS - abs_err_old[5];
PID_Cal_Limt( &motor.PID_SPEED[6], 10, abs_err[5], motor.PID_ANGLE[6].OUT);
abs_err_old[5] = motor.ANGLE[5].POS_ABS;
Motor_Set_Current2((int16_t)(motor.PID_SPEED[6].OUT) ,0,0,0);
}
else
}
这个部分有几个小细节主要注意:
1.角度控制一套PID参数即可,为了不损害机械机构所以我写了两套PID参数来控制电机的发射和回收。
2.motor_err()是电机角度死区控制,目的是防止电机在目标角度附件来回跳动。
3. 角度控制的主要流程是先将目标角度在角度环里计算,将角度环的输出发送给速度环,再将速度环的输出发射给电调即可。
4. 一般串级PID的调参主要是调角度环,如果需要电机的爆发力很大,角度环的输出限制不能设置的很大。
5.若是电机在目标值附近来回震动很大,则需要在角度环里加大d的值。
6.角度环的程序需要放在 投射电机 的can接收中断里。
if((rx_message.StdId == (MOTOR_ID_READ+5)) ) //电机5
{
Motor_Auto_Run(); //串级PID 3508 正方向-向上
MOTOR_FEEDBACK[5].angle_value = rx_message.Data[0] << 8 | rx_message.Data[1];
MOTOR_FEEDBACK[5].speed_rpm = rx_message.Data[2] << 8 | rx_message.Data[3];
MOTOR_FEEDBACK[5].real_current = rx_message.Data[4] << 8 | rx_message.Data[5];
MOTOR_FEEDBACK[5].temperature = rx_message.Data[6];
MOTOR_FEEDBACK[5].real_angle = MOTOR_FEEDBACK[5].angle_value/8192.0f*360.0f;
}
上文若有错误,请指正。
今天的文章大疆电机转速_大疆fpv限速分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/86638.html