说说 这里是学习部分知识的记录
总线370电机介绍
电源:
总线接口既是通信接口又是电源输入接口,输入电源范围 DC:6-12V
通信接口和电源接口共用一个接口,其中 VCC/GND 表示电源引脚,DATA 是信号引脚
【工作灯】:
输入电源正常工作时,指示灯 1S 闪烁一次即为正产,常亮或者常灭均有问题,需立即拔下电源检查问题所在。【转向灯】:
当一个灯亮起时的转动定义正向转动时,另一个灯亮起即表示反向转动。
B (测速信号)``CH1 (驱动信号)``CH2 (驱动信号)``A (测速信号)
麦克纳姆轮控制原理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 ''' 通过串口发送指令控制电机的转速,时间 参数: speed_l1---左前轮 speed_r1---右前轮 speed_l2---左后轮 speed_r2---右后轮 (-1000~1000)负值后退,正值前进,绝对值越大转速越高。 time 代表车轮转动时间,0 代表一直转动,1000 代表转动 1 秒,以此类推。 ''' def car_run (speed_l1,speed_r1,speed_l2,speed_r2,time ): textSrt = '#006P{0:0>4d}T{4:0>4d}!#007P{1:0>4d}T{4:0>4d}!#008P{2:0>4d}T{4:0>4d}!#009P{3:0>4d}T{4:0>4d}!' .format (1500 +speed_l1,1500 -speed_r1,1500 +speed_l2,1500 -speed_r2,time) print (textSrt) myUart.uart_send_str(textSrt) def car_stop (): myUart.uart_send_str('#006P1500T1000!#007P1500T1000!#008P1500T1000!#009P1500T1000!' ) def car_text (): car_run(400 ,400 ,400 ,400 ,1000 ) time.sleep(1 ) car_run(-400 ,-400 ,-400 ,-400 ,1000 ) time.sleep(1 ) car_run(-400 ,400 ,-400 ,400 ,1000 ) time.sleep(1 ) car_run(400 ,-400 ,400 ,-400 ,1000 ) time.sleep(1 ) car_run(-400 ,400 ,400 ,-400 ,1000 ) time.sleep(1 ) car_run(400 ,-400 ,-400 ,400 ,1000 ) time.sleep(1 ) car_stop()
自由避障代码讲解 超声波传感器原理:
采用 IO 触发测距,给至少 10us 的高电平信号;
模块自动发送 8 个 40khz 的方波,自动检测是否有信号返回; 有信号返回,通过 IO 输出一高电平,高电平持续的时间就是超声波从发射到返回的时间.测试距离=(高电平时间*声速(340M/S))/2;
工作原理:
超声波传感器检测距离,小于 30cm 时左转,判断 mode 的值使指令只发送一次
1 2 3 4 5 6 7 8 9 10 11 12 13 14 def obstacle_avoidance (): global systick_ms_bak,dis,mode if (int ((time.time() * 1000 ))- systick_ms_bak > 100 ): systick_ms_bak = int ((time.time() * 1000 )) dis = myUls.distance() dis = int (dis) if 30 >= dis and mode != 1 : myCar.car_run(400 ,400 ,400 ,400 ,0 ) mode = 1 elif dis < 30 and mode != 2 : mode = 2 myCar.car_run(-400 ,400 ,-400 ,400 ,2000 ) myBeep.beep(1 ,1 )
跟随模式代码讲解 代码逻辑:
dis 获取超声波检测的距离,单位 cm,小于 15cm 时后退,在 15-35 范围内和大于 60cm 时停止,在 35-60cm 内前进,判断 mode 的值使指令发送一次
1 2 3 4 5 6 7 8 9 10 11 12 13 14 def nterval_follow (): global systick_ms_bak,dis,mode if (int ((time.time() * 1000 ))- systick_ms_bak > 100 ): systick_ms_bak = int ((time.time() * 1000 )) dis = myUls.distance() if dis < 15 and mode != 1 : myCar.car_run(-400 ,-400 ,-400 ,-400 ,0 ) mode = 1 elif (15 <= dis <= 35 or dis > 60 ) and mode != 2 : mode = 2 myCar.car_stop() elif 35 < dis <= 60 and mode != 3 : myCar.car_run(400 ,400 ,400 ,400 ,0 ) mode = 3
总线舵机介绍 舵机参数
舵机供电范围 4.8-8.4V。
扭力 15kg/cm。
八种角度工作模式,270 度角度控制正反转、180 度角度控制正反转、360 度定圈连续旋转正反转、360 度定时连续旋转正反转八种工作模式可切换,同一个舵机可在这八种角度工作模式下供用户切换。
单总线通讯,波特率 115200,舵机之间通过总线串联。 每个舵机都有自己 ID 号,
舵机默认 ID 为 0,用户可通过命令改变舵机 ID,255 代表广播地址。
可回读角度,用户可读取舵机当前实时位置。
串口指令控制,无需用户编写舵机 PWM 驱动程序, 控制简单。
注意:所有的 ID 号必须是 3 位,不够用 0 补齐,例如 1 号,则 001,PWM 位 4 位,不够用 0 补齐, 例如 500 则 0500,Time 4 位,例如 20,则为 0020,最大时间位 9999ms.
1、#000P1500T1000!
解析 :“#”和“!”是固定英文格式。000 代表 ID(范围 0-254),必须为 3 位,不足补 0。比如 3 号舵机为“003”而不能为“3”。1500 代表 PWM 脉冲宽度调制(P)(范围 500-2500), 必须为 4 位,不足补 0。比如 PWM 为 800,则必须为“P0800”。1000 代表 TIME 时间(T)(范围 0-9999),同样必须为 4 位,不足补 0,单位 ms。比如 TIME 为 500,则必须为“T0500” 该指令可以叠加同时控制多个舵机。多个指令同时使用时(2 个或 2 个以上叠加)需要在整条指令前后加“{}”,比如:{G0000#000P1602T1000!#001P2500T0000!#002P1500T1000!}
2、#000PVER!
解析:读取舵机版本号,返回格式为:#000PV0.97!
3、#000PID!
4、#000PID001!
解析:指定ID检测,该指令时读取000的ID,检测当前舵机是否为000 这个ID号,是返回#000P!。 否则无返回,当不知道舵机 ID 时,发送#255PID! 可返回舵机 ID 号。
解析:指定修改 ID,该指令是把 000 号 ID 改为 001 号,修改成功后返回#001P!。不成功无返回。
5、#000PULK!
解析:释放后舵机处于制动状态,此时可以用手扳动舵机旋转。在纠正舵机偏差和手动编程时会用到此功能,成功返回 #OK!。
6、#000PULR!
解析:恢复扭力,以舵机当前的位置恢复扭力,成功返回#OK!
7、#000PMOD!
解析:读取舵机当前的工作模式,返回如下:
#000PMOD1! :舵机模式,角度最大范围 270 度,方向顺时针
#000PMOD2! :舵机模式,角度最大范围 270 度,方向逆时针
#000PMOD3! :舵机模式,角度最大范围 180 度,方向顺时针
#000PMOD4! :舵机模式,角度最大范围 180 度,方向逆时针
#000PMOD5! :马达模式,角度 360 度,定圈旋转,方向顺时针
#000PMOD6! :马达模式,角度 360 度,定圈旋转,方向逆时针
#000PMOD7! :马达模式,角度 360 度,定时旋转,方向顺时针
#000PMOD8! :马达模式,角度 360 度,定时旋转,方向逆时针
8、#000PMOD1!
解析:设置舵机工作模式,默认工作模式为 1 1:舵机模式 270 度顺时针 2:舵机模式 270 度逆时针 3:舵机模式 180 度顺时针 4:舵机模式 180 度逆时针 5:马达模式 360 度定圈顺时针模式 6:马达模式 360 度定圈逆时针模式 7:马达模式 360 度定时顺时针模式 8:马达模式 360 度定时逆时针模式设置成功均返回#OK!
关于定圈定时问题解释:定圈模式: 若指令为 #000P1800T1000! 表示以 300(1800-1500)的速度,运行 1000 圈后停止,允许误差存在。若 T=0000! 则表示以 300(1800-1500)的速度无限循环执行。定时模式: 若指令为 #000P1800T1000! 表示以 300(1800-1500)的速度,运行 1000S 后停止, 允许误差存在。若 T=0000! 则表示以 300(1800-1500)的速度无限循环执行。
9、#000PRAD!
解析:读取舵机当前位置,返回格式为#000P1500!
10、#000PDPT!
解析:暂停,舵机运行过程中接收此指令,会停止当前,再接收继续指令后,会接在当前位置继续运行,成功返回 #OK!
11、#000PDCT!
解析:配合暂停指令继续操作,比如#001P2500T5000! 发送给舵机,在 2000ms 的时候发送了#000PDPT! 指令给舵机,则舵机暂停,保持力矩在停止的位置,再发送#000PDCT!给舵机,则舵机继续剩余的 3000ms 结束,成功返回 #OK!
12、#000PDST!
解析:停止在当前位置,与暂停指令不同的事,之后无法继续执行,需重新执行,返回#OK!
13、#000PBD1!
解析:设置舵机通信波特率,默认 115200。数字参数对应关系为:1-9600,2-19200,3-38400,4-57600,5-115200,6-128000,7-256000,8-1000000,该指令设置成功后返回#000PBD9600!。
14、#000PSCK!
解析:用于纠正偏差,将当前位置设置为 1500 中间值,成功返回 #OK!
15、#000PCSD!
解析:设置舵机启动位置,默认 1500,开机自启动范围为 0500~2500,成功返回 #OK!
16、#000PCSM!
解析:去除初始值,使用该命令后,#000PCSD! 指令失效,舵机启动释力状态。成功返回 #OK!
17、#000PCSR!
解析:恢复初始值,使用该命令后,舵机启动恢复力矩,#000PCSD! 指令恢复,转到初始值,成功返回 #OK!
18、#000PSMI!
解析:设置舵机最小值,最小值默认为 0500,将舵机调节到合适位置后,发送此命令设置。 成功返回#OK!
19、#000PSMX!
解析:设置舵机最大值,最大值默认为 2500,将舵机调节到合适位置后,发送此命令设置。成功返回#OK!
20、#000PCLE!
解析:全恢复出厂设置,ID 号恢复 000,舵机模式默认 1、波特率默认 115200、初始值 1500、矫正值 1500、最小值 0500、最大值 2500,成功返回 #OK!
21、#000PRTV!
解析:获取温度和电压,成功返回 #000T25V07! 舵机的 ID 默认是 0, ID 为 255 是广播模式, 广播命令对所有舵机都有效。
22、#000PSTB!
解析:读取设置温度和电压。
23、#000PSTB=60!
解析:设置释放扭力阈值温度为 60
注意事项
舵机默认 ID 为 0, 用户在使用前需要修改 ID, 使每个舵机 ID 号不一样, 否则舵机串联后所有舵机都会同时运动。 修改 ID 时候舵机不要串联, 当所有要使用舵机 ID 修改完毕后, 在将舵机串联即可。
机械臂之逆运动学控制 机械臂正逆运动学认识:
正运动学分析是已知每个关节的姿态的前提下,解算出末端执行器的姿态。而逆运动学研究的问题是,要求控制末端执行器到达某一位置时,各关节应处于什么姿态。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 import syssys.path.append('/home/pi/Desktop/ZL-PI/factory_code/' ) import timeimport ZL_SDK.z_beep as myBeepimport ZL_SDK.Z_UartServer as myUartimport AI_Functions.z_kinematics as kmsmyBeep.setup_beep() myUart.setup_uart(115200 ) ''' 设置四个关节的长度 单位 0.1mm 底盘到第二个舵机中心轴的距离 第二个舵机到第三 个舵机的距离 第三个舵机到第四 个舵机的距离 第四个舵机到机械臂(闭合后)最高点的距离 ''' kms.setup_kinematics(170 ,105 ,75 ,185 ) myUart.uart_send_str("#255P1500T1000!" ) time.sleep(2 ) myBeep.beep(3 ,0.1 ) '''输入参数:x,y,z,time 以机械臂的视角来看: 左右为 x 轴,右为正值,单位毫米; 前后为 y 轴,前为正值,y 值不能小于 0,单位毫米; z 为高度,单位毫米; time 为机械臂运行到目标位置的时间,单位毫秒。 若输出为{#000P0000T1000!#001P0000T1000!#002P0000T1000!#003P0000T1000!}。说明机械臂无法达到目标位置。 ''' kms.kinematics_move(0 ,100 ,150 ,1000 ) time.sleep(2 ) kms.kinematics_move(0 ,200 ,200 ,1000 ) time.sleep(2 ) kms.kinematics_move(0 ,300 ,50 ,2000 ) time.sleep(3 ) myUart.uart_send_str("#255P1500T2000!" )
颜色追踪代码讲解 颜色识别的流程:
第一步: 高斯滤波使图片模糊,减小图像噪点;第二步: 将 BGR 模型转换为 HSV 模型, RGB 模型适合显示,但却并不适合作为颜色识别的模型。HSV 更加符合人眼的感受,将其作为颜色识别的模型会大大提高识别的鲁棒性,因为 HSV 模型颜色识别大大减少了对环境光的依赖。第三步: 设置阈值,去除背景,保留所设置的颜色。第四,五步: 对图像进行开运算,先腐蚀后膨胀,移除由图像噪声形成的斑点。第六步: 通过边缘检测获取识别到物体的中心点坐标,及长宽。
根据物体在画面中的相对坐标判断物体的位置,换算成 pwm 值,通过(#000P1500T1000!)控制指令控制舵机或电机转动
Flag 变量为真时是机械臂跟随模式,为假时是车体跟随模式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 def color_detect (frame,color,flag ): global x_bias,y_bias,c_h,c_w,width,hight frame = cv2.resize(frame, (320 ,240 ), interpolation = cv2.INTER_CUBIC) frame = cv2.GaussianBlur(frame,(5 ,5 ),0 ) hsv = cv2.cvtColor(frame,cv2.COLOR_BGR2HSV) mask = cv2.inRange(hsv, color_dist[color]['Lower' ], color_dist[color]['Upper' ]) mask = cv2.erode(mask,None ,iterations=2 ) mask = cv2.dilate(mask, cv2.getStructuringElement(cv2.MORPH_RECT, (3 , 3 ))) cnts = cv2.findContours(mask.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)[-2 ] if len (cnts) >0 : cnt = max (cnts,key=cv2.contourArea) rect = cv2.minAreaRect(cnt) box = cv2.boxPoints(rect) cv2.drawContours(frame, [np.int0(box)], -1 , (0 , 255 , 255 ), 2 ) c_x, c_y = rect[0 ] c_h, c_w = rect[1 ] c_angle = rect[2 ] x_bias = c_x - width/2 y_bias = c_y - hight/2 area = c_h*c_w 39. print (time.time(), 'x=' , int (c_x), 'y=' , int (c_y), 'c_h=' , int (c_h),'c_w=' , int (c_w), 'angle=' , int (c_angle)) if 30 < c_h < 150 and 30 < c_w < 150 : if flag: camera_follow(x_bias,y_bias) else : car_follow(x_bias,area) return frame
视觉循迹代码讲解 工作流程:
颜色识别流程参考第二课,在视觉循迹代码中不同的是查找轮廓的方法不同。 使用 cv2.CHAIN_APPROX_NONE 存储轮廓所有的点,然后寻找轮廓质心,根据轮廓质心在画面中的位置控制车辆移动。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 def car_tracking (frame,color ): global cx,cy frame = cv2.resize(frame,(160 ,60 ),interpolation = cv2.INTER_CUBIC) frame = cv2.GaussianBlur(frame,(5 ,5 ),0 ) hsv = cv2.cvtColor(frame,cv2.COLOR_BGR2HSV) mask = cv2.inRange(hsv, color_dist[color]['Lower' ], color_dist[color]['Upper' ]) mask = cv2.erode(mask,None ,iterations=2 ) mask = cv2.dilate(mask, None , iterations=2 ) mask = cv2.GaussianBlur(mask,(3 ,3 ),0 ) image,contours,hierarchy = cv2.findContours(mask.copy(), 1 , cv2.CHAIN_APPROX_NONE) if len (contours) > 0 : c = max (contours, key=cv2.contourArea) M = cv2.moments(c) 26. cx = int (M['m10' ]/M['m00' ]) cy = int (M['m01' ]/M['m00' ]) Tracing(cx) else : pass return frame
人脸追踪代码讲解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 face_cascade = cv2.CascadeClassifier('/home/pi/Desktop/car_code/AI_Functions/face.xml' ) def camera_follow (x,y ): global pwm_value1,pwm_value2 x_bias = x - width/2 y_bias = y - hight/2 pwm_value1 = pwm_value1 - x_bias//5 pwm_value2 = pwm_value2 - y_bias//5 TextStr = '#000P%04dT0000!#003P%04dT0000!' % (pwm_value1,pwm_value2) print (TextStr) myUart.uart_send_str(TextStr) def face (frame ): frame = frame frame = cv2.resize(frame, (320 ,240 ), interpolation = cv2.INTER_CUBIC) 将图片缩放到 320 *240 gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) faces = face_cascade.detectMultiScale(gray,1.1 ,5 ) debug = True findOk = 0 for (x,y,w,h) in faces: cv2.rectangle(frame,(x,y),(x+w,y+h),(255 ,0 ,0 ),2 ) roi_gray = gray[y:y+h, x:x+w] roi_color = frame[y:y+h, x:x+w] x = int (x+w/2 ) y = int (y+h/2 ) findOk = 1 if findOk == 1 : print ('time:' ,time.time(), ' x=' ,x, ' y=' ,y) camera_follow(x,y) return fram
太阳能板的选择 电池参数分析
电压(Voltage) :7.4V
容量(Capacity) :5200mAh(或5.2Ah)
放电倍率(Discharge Rate) :25C
其中,放电倍率25C意味着电池可以在1/25小时内完全放电,即理论上可以在2.4分钟内放电完毕。但实际上,这样的高倍率放电主要用于短时间的高功率应用,如电动工具或赛车。对于太阳能充电系统,我们主要关心的是电池的电压和容量。
太阳能板选择
电压 :太阳能板的输出电压应略高于电池电压,以保证充电效率。因此,一个输出电压为8V到12V的太阳能板是比较合适的。
电流 :电池的容量是5.2Ah,但太阳能板提供的电流会随光照强度而变化。在理想情况下,太阳能板在最大光照时的电流应至少为电池容量的1/3到1/2,即1.73A到2.6A。然而,由于太阳能板的输出电流会随光照条件变化,因此实际选择时可以考虑稍大一些的太阳能板。
功率 :太阳能板的功率(瓦特)是电压和电流的乘积。根据上述分析,一个功率在80W到150W之间的太阳能板可能是合适的。
充电控制器选择
电压和电流兼容性 :充电控制器应能处理太阳能板的输出电压和电流。因此,选择一个兼容8V到12V电压和至少2.6A电流的充电控制器是必要的。
充电模式 :充电控制器通常有几种充电模式,如恒流充电、恒压充电和涓流充电。选择具有这些基本充电模式的控制器可以满足大多数应用需求。
保护功能 :充电控制器应具备过充、过放、反接和短路保护等基本功能,以保护电池和整个系统的安全。
总结 需要选择一个输出电压为8V到12V,功率为80W到150W的太阳能板,以及一个兼容这些参数的充电控制器。