前面写了单个舵机的简单控制程序,下面做多个舵机的控制。
单个舵机控制写完,就将单个舵机堆成一组舵机,先从2台舵机开始。
将舵机参数生成一个结构体:
// 舵机参数
struct SE_Par
{
hi_u16 an1; // 当前角度
hi_u16 an2; // 转向角度
hi_u16 lef; // 左边界
hi_u16 mid; // 中间
hi_u16 rig; // 右边界
hi_u8 pin; // 端口
hi_u8 run; // 运行 0 1
hi_u8 spa; // 跨度 0 1 10
hi_u8 del; // 延时 0 1
hi_u8 dir; // 方向 0 1
};
然后声明一个舵机参数的数组,这样就得到了一组舵机。将舵机初始化:
struct SE_Par se_ps[SE_PN] = {0}; // 舵机参数
hi_u8 se_pi = 0; // 舵机端口
// 舵机参数初始化
hi_void Engine_Init(hi_void)
{
for(hi_u8 i = 0; i < SE_PN; i++)
{
se_ps[i].pin = i;
se_ps[i].run = 0;
se_ps[i].spa = 0;
se_ps[i].dir = 0;
se_ps[i].del = 0;
se_ps[i].an1 = 135;
se_ps[i].an2 = 135;
se_ps[i].lef = 0;
se_ps[i].mid = 135;
se_ps[i].rig = 270;
PCA9685_Angle(se_ps[i].pin, se_ps[i].an1, 270);
}
}
每台舵机初始化完,将舵机转向居中。
剩下的就是在运行的时候,先通过遥控器设置舵机端口,然后控制相应的舵机的运行。就跟控制单位舵机一样的了。
// 遥控 控制
hi_u8 RC_Control(hi_u8 con)
{
hi_u8 ret = 1;
// 设置跨度
// 0xa2, 1
if(con == 0xa2)
{
printf(" 1 : \n");
se_ps[se_pi].spa = 0;
}
// 0x62, 2
if(con == 0x62)
{
printf(" 2 : \n");
se_ps[se_pi].spa = 1;
}
// 0xe2, 3
if(con == 0xe2)
{
printf(" 3 : \n");
se_ps[se_pi].spa = 10;
}
// 设置边界
// 左
// 0x22, 4
if(con == 0x22)
{
printf(" 4 : \n");
if(se_ps[se_pi].dir == 0)
{
se_ps[se_pi].lef = se_ps[se_pi].an1;
}
if(se_ps[se_pi].dir == 1)
{
se_ps[se_pi].rig = se_ps[se_pi].an1;
}
}
// 中
// 0x02, 5
if(con == 0x02)
{
printf(" 5 : \n");
se_ps[se_pi].mid = se_ps[se_pi].an1;
}
// 右
// 0xc2, 6
if(con == 0xc2)
{
printf(" 6 : \n");
if(se_ps[se_pi].dir == 0)
{
se_ps[se_pi].rig = se_ps[se_pi].an1;
}
if(se_ps[se_pi].dir == 1)
{
se_ps[se_pi].lef = se_ps[se_pi].an1;
}
}
// 旋转方向设置
// 0xe0, 7
if(con == 0xe0)
{
printf(" 7 : \n");
if(se_ps[se_pi].dir == 0)
{
se_ps[se_pi].dir = 1;
}else{
se_ps[se_pi].dir = 0;
}
}
// 0xa8, 8
if(con == 0xa8)
{
printf(" 8 : \n");
}
// 运行延时开关
// 0x90, 9
if(con == 0x90)
{
printf(" 9 : \n");
if(se_ps[se_pi].del == 0)
{
se_ps[se_pi].del = 1;
}else{
se_ps[se_pi].del = 0;
}
}
// 运行到中间
// 0x98, 0
if(con == 0x98)
{
printf(" 0 : \n");
se_ps[se_pi].an2 = se_ps[se_pi].mid;
se_ps[se_pi].run = 1;
}
// 退出
// 0x68, *
if(con == 0x68)
{
printf(" * : \n");
ret = 0;
}
// 重置
// 0xb0, #
if(con == 0xb0)
{
printf(" # : \n");
se_ps[se_pi].an1 = 135;
se_ps[se_pi].an2 = 135;
se_ps[se_pi].lef = 0;
se_ps[se_pi].mid = 135;
se_ps[se_pi].rig = 270;
}
// 端口切换
// 0x18, up
if(con == 0x18)
{
printf(" up : \n");
if(se_pi < (SE_PN - 1))
{
se_pi++;
}
}
// 0x4a, down
if(con == 0x4a)
{
printf(" down : \n");
if(se_pi > 0)
{
se_pi--;
}
}
// 向左运行
// 0x10, left
if(con == 0x10)
{
printf(" left : \n");
if(se_ps[se_pi].dir == 0)
{
se_ps[se_pi].an2 = Turn_Left(se_ps[se_pi]);
}
if(se_ps[se_pi].dir == 1)
{
se_ps[se_pi].an2 = Turn_Right(se_ps[se_pi]);
}
se_ps[se_pi].run = 1;
}
// 向右运行
// 0x5a, right
if(con == 0x5a)
{
printf(" right : \n");
if(se_ps[se_pi].dir == 0)
{
se_ps[se_pi].an2 = Turn_Right(se_ps[se_pi]);
}
if(se_ps[se_pi].dir == 1)
{
se_ps[se_pi].an2 = Turn_Left(se_ps[se_pi]);
}
se_ps[se_pi].run = 1;
}
// 运行停止
// 0x38, OK
if(con == 0x38)
{
printf(" OK : \n");
if(se_ps[se_pi].run == 1)
{
se_ps[se_pi].run = 0;
se_ps[se_pi].an2 = se_ps[se_pi].an1;
}
}
// 显示信息
Display_SE_Data();
return ret;
}
但是多台舵机的控制,遇到几个问题:
第一个是边界问题,舵机组合到一起,工作范围需要设定,否者容易出现砸机的问题,还有就是舵机本身是机械装置,输出的居中位置,在机械齿轮上输出并不一定真的居中,这个时候就要先设置居中位置。
第二个是方向问题,比如你按遥控的左键,你看到的舵机是右转,舵机的转向方向是固定的,操作习惯认为是反的,这个时候我添加一个方向的参数,可以按右键的时候向左转,就是将舵机的工作模式进行镜像的操作。
第三个问题是,代码堆到一定程度,就很难维护,一个函数里关联的参数太多,需要修改功能的时候,就连带的改动很大,搞不好就要推倒重写,所以函数的功能独立,将代码解耦到可控的程度。
遥控舵机演示
遥控器发送指令,控制舵机转到想要的位置,然后将这个位置设定为边界,这样舵机就不会越出工作范围。2台舵机分别控制。
舵机多了,组合工作靠遥控器就不行了,下一步写网络功能。