PCA9685模块16路舵机控制板,作为执行器控制板zr_pwm16_pca9685包可以用ros srv来控制扩展板上的舵机。
逻辑电压3~5v
I2c通讯
使能
动力供电压最大6V的说,试验功率较的大舵机8V没异常,(像sg90 9g这种不要冒险,电压高了舵机可能会冒烟的)。
video
https://www.bilibili.com/video/BV1C7411C75B/
硬件节点
rospy.Service('zr_hw_cmd', hw_cmd, fun1)
ros节点
srv_name='zr_hw_cmd'
rospy.wait_for_service(srv_name)
srv 发送初始角位。ps(data) 返回ok
srv 使能。en() en(1||0)返回en状态"0",“1”
/----------------------------------------------------------------------/
hw_cmd.srv
string cmd
uint8[] input
---
uint8[] output
cmd命令支持的字符串有:“n”,“v”,“b”,“c”,“ps”,“en”
n代表name
v代表version
b代表brand
c代表copyright
ps代表 position set 执行ps(input)
en代表 模块使能 en()返回使能状态 en(0||1)设置并返回使能状态,使能后舵机才会运动。
sm代表 慢速连续运动 平滑 sm(0||1)设置并返回平滑状态
使用平滑sm(1),应先开启en(1),再发送数据。
sm 开启时段内只能控制某一个控制板所有端口的运动平滑。如果在运动结束之前,关闭了sm,会导致平滑失效,目标角位迅速到达。
脉冲的频率、脉宽与input的数据格式的定义
//50hz 相当于20ms(20000us)的 周期, 4096分辨率,分辨率每单位占用时间t 为20000us/4096=4.8828125us
//舵机控制所需脉宽Th范围0.5 ~ 2.5ms(500 ~ 2500us)因此高电平分辨率范围就是Th/t =(102.4~512)个单位。
500/ 200004096=102.4
2500/ 200004096=512
500/4.8828125=102.4
2500/4.8828125=512
//取整 最小103 最大512 范围是512-103=409;
#define SERVO_0 103
#define SERVO_45 205
#define SERVO_90 308
#define SERVO_135 410
#define SERVO_180 512
数据范围是0~ 409,对应脉宽单位103~ 512,对应舵机角度0~ 180
数据使用一个字节
因为“一个字节”范围是0~255, 当使用低精度数据时,通讯时资源占用会少,舵机角位精度减半,
一个字节不是0~ 255对应0~ 180;
由于舵机精度不一,为了校准方便,
硬件程序根据数据来控制脉宽,可实现软校准。
数据范围之外有一个软校准上下调整的范围,硬件内定为8;
精度减半,数据d值在硬件内再加上软校准调整范围8,再乘以2; (d+8)2=(103 ~ 512)
最值这样求
dmin2+16=103;dmin=44
dmax*2+16=512;dmax=248
这样 44 ~ 248就 对应脉宽单位103 ~ 512,对应舵机角度0 ~ 180;
校准应根据实际情况,在44~248的基础范围上做适当缩放和偏移。
注意:软校准调整范围时不能跳跃过大,比如突然发送1或255,没有保护措施这样做有可能损坏舵机!损坏舵机! 损坏舵机!
数据使用两个字节,数据范围 0 ~ 65535,实际使用103 ~ 512,舵机精度提高 ,d=(103~512)
dmin=103;
dmax=512;
校准应根据实际情况,在103~512的基础范围上做适当缩放和偏移。
注意:软校准调整范围时不能跳跃过大,比如突然发送1或1024,没有保护措施这样做有可能损坏舵机!损坏舵机! 损坏舵机!
定义数据包
目标: 1控制单个端口, 2控制相邻的一系列的端口,控制数据精度
硬件地址: 6bit AAAAAA(取值对应板上焊盘焊点)
端口号 : 4bit pppp
数据精度:2bit TT 每个数据的size 根据TT值确定分别为8位低精度或16位高精度分辨率,即0 - 256或0-65535
字节数据包格式
|--------|--------|--------|--------|--------|--------|--------|...
|TTAAAAAA|----pppp|ddddddd0|ddddddd1|ddddddd2|ddddddd3|ddddddd4|...
TTAAAAAA----pppp占两个字节为包头,定义数据分辨率TT,定义了起始地址和端口,就可以找到对应控制板的几号端口。
单字节数据
TT=0,AAAAAA=0,pppp=0
|00000000|----0000|ddvalue0|ddvalue1|ddvalue2|ddvalue3|ddvalue4|ddvalue5|...
0x00,0x00,0xxx,0xxx,0xxx,0xxx,0xxx,0xxx...
双字节数据
TT=1,AAAAAA=0,pppp=0
|01000000|----0000|dvalue0H|dvalue0L|dvalue1H|dvalue1L|dvalue2H|dvalue2L|dvalue3H|dvalue3L|dvalue4H|dvalue4L|dvalue5H|dvalue5L|...
0x40,0x00,0xxx,0xxx,0xxx,0xxx,0xxx,0xxx,0xxx,0xxx,0xxx,0xxx,0xxx,0xxx...
单字节数据,硬件地址1,端口15
TT=0,AAAAAA=1,pppp=15
|00000000|----0000|ddvalue0|ddvalue1|ddvalue2|ddvalue3|ddvalue4|ddvalue5|...
0x01,0x0f,0xx1,0xx2,0xx3,0xx4,0xx5,0xx6...
注意:0xx1为1号板15号端口的数据,多余的数据,会发送到下一个硬件地址(+1)的对应端口(0-15),
1号板15号:0xx1
2号板00号:0xx2
2号板01号:0xx3
2号板02号:0xx4
2号板03号:0xx5
2号板04号:0xx6
…
依次类推。
因此上位机有比较灵活的控制方式。
还需注意:因为单片机通讯缓存区大小为固定值,所以ROS消息的大小不能超过300字节,
当发送单字节数据时每个ROS消息最多可以控制256个端口
当发送双字节数据时每个ROS消息最多可以控制128个端口
当级联板数量较多(>8或>16个)时,可以拆分两个消息进行控制。
开启 sm 后只能控制单个板所有端口的运动平滑,一次应发送16个端口的数据。不支持跨板和指定端口号的控制
示例代码
roslaunch zr_pwm16_pca9685 pwm16_demo.launch
roslaunch zr_pwm16_pca9685 pwm16_fake.launch
video
https://www.bilibili.com/video/BV1C7411C75B/
gitbub
https://github.com/zaizhizhuang/zr