在机器人运动中,电机控制为最重要的部分之一,机器人的各种运动都离不开电机的运作。写程序的时候最忌讳重复造轮子,这里就以已有的步兵标准代码为例,利用已经实现的方法对电机进行一些控制。
我们常用的电机有三种M3508电机(需搭配C6020电调使用)、GM6020电机、M2006电机(需搭配C6010电调使用)
头文件
电机类头文件为 motor.h ,里面构造了实现了电机类的一些实现
参数定义
constexpr auto MAXSPEED = 4000;
constexpr auto ADJUSTSPEED = 3000;
enum { ID1 = 0x201, ID2, ID3, ID4, ID5, ID6, ID7, ID8};
enum { pre = 0, now };
enum pid_mode{ speed = 0, position };
enum motor_type{ M3508, M3510, M2310, EC60, M6623, M6020 }; //M2310也是M2006
enum motor_mode { SPD, POS, ACE };
#define SQRTF(x) ((x)>0?sqrtf(x):-sqrtf(-x))
#define T 1.e-3f
该部分为一些数值的预定义,包括一些ID的值枚举,ID代表着各个电机的标识符,具体数据见 电机参数
Motor类
class Motor
{
/*具体实现*/
}
public部分中定义了电机的构造函数,电机控制方法、以及电机的三种操作模式
构造函数
//构造函数1:需填入五个参数; 电机运动过程由速度环与位置环共同调节
//一般在GM6020电机上使用此构造函数
Motor(const type_t type,const motor_mode mode,const uint32_t id, PID _speed, PID _position)
: ID(id)
, type(type)
, mode(mode)
{
getmax(type);
memcpy(&pid[speed], &_speed, sizeof(PID));
memcpy(&pid[position], &_position, sizeof(PID));
}
//构造函数2:需填入4个参数; 电机运动过程仅由速度环调节
//一般在M3508、M2006电机上使用此
Motor(const type_t type, const motor_mode mode, const uint32_t id, PID _speed)
: ID(id)
, type(type)
, mode(mode)
{
getmax(type);
memcpy(&pid[speed], &_speed, sizeof(PID));
}
具体实现
/*
*根据电机模型来实现其功能
*para1: idata[][8]电调的接受报文
*para2: odata 输出报文
*实现功能:可以根据C620电调的收发报文控制电机的运转
*/
void Ontimer(uint8_t idata[][8], uint8_t* odata)
{
const uint32_t ID = this->ID - ID1;
angle[now] = getword(idata[ID][0], idata[ID][1]);
if(type == EC60)curspeed = static_cast<float>(getdeltaa(angle[now] - angle[pre])) / T / 8192.f * 60.f;
else curspeed = getword(idata[ID][2], idata[ID][3]);
///angle[pre]&angle[now]&curspeed are available.
if(mode == ACE)//accurate mode
{
curcircle += getdeltaa(angle[now] - angle[pre]);
if (spinning)
{
const int32_t diff = curcircle - setcircle;
if (std::fabs(diff) >= 4096) setspeed = -adjspeed * SQRTF((float)diff / (float)spinning);
else
{
// = std::fabs(diff);
setangle = 8192 + ((diff < 0) ? -1 : 1)*(std::abs(diff) % 8192);
spinning = 0;
}
}
else
{
setcircle = curcircle;
const float error = getdeltaa(setangle - angle[now]);
if (std::fabs(error) < 30.f)setspeed = 0.0;
else
{
setspeed = pid[position].Position(//pid[position].Filter(
getdeltaa(setangle - angle[now]));
setspeed = setrange(setspeed, maxspeed);
}
}
current += pid[speed].Delta(setspeed - curspeed);
current = setrange(current, maxcurrent);
}
else if(mode == POS)//position mode
{
const float error = getdeltaa(setangle - angle[now]);
//if (fabs(error) < 30.f)setspeed = 0.0;
//else
{
setspeed = pid[position].Position((
getdeltaa(setangle - angle[now])));
setspeed = setrange(setspeed, maxspeed);
}
current = pid[speed].Position(setspeed - curspeed);
current = setrange(current, maxcurrent);
}
else if(mode == SPD)//speed mode
//proceed speed any way.
{
current += pid[speed].Delta(setspeed - curspeed);
current = setrange(current, maxcurrent);
}
angle[pre] = angle[now];
odata[ID * 2] = (current & 0xff00) >> 8;
odata[ID * 2 + 1] = current & 0x00ff;
}
还有一些其他的功能函数
/*
*用于根据电机型号返回上限值
*/
void getmax(const type_t type)
{
adjspeed = 3000;
switch(type)
{
case M3508:
case M3510:
maxcurrent = 13000;
maxspeed = 9000;
break;
case M2310:
maxcurrent = 13000;
maxspeed = 9000;
break;
case EC60:
maxcurrent = 5000;
maxspeed = 300;
break;
case M6623:
maxcurrent = 5000;
maxspeed = 300;
break;
case M6020:
maxcurrent = 30000;
maxspeed = 80;
adjspeed = 80;
break;
default:;
}
}