今日继续学习树莓派4B 4G:(Raspberry Pi,简称RPi或RasPi)
本人所用树莓派4B 装载的系统与版本如下:
版本可用命令 (lsb_release -a) 查询:
Opencv 版本是4.5.1:
Python 版本3.7.3:
今日尝试搭建一台小车,外观自行设计、树莓派主控、自行挑选模块 ,完成简单的巡线动作,就开环控制了,这篇文章的使用就不闭环了......
巡线的思想就是在视频屏幕最下方1/4的ROI区域灰度识别黑色色块,计算与中点的偏差,与中点偏差的像素过大就原地左右转调整,其余识别到黑线在偏差范围内不大时就正常走直线
自评:原地左右转以及没使用PID闭环使得这个视觉巡线小车看起来不太智能,还可改进>>>
文章提供测试代码讲解,整体代码贴出、测试效果图、完整测试工程下载
目录
小车外观与使用模块:
搭个小车还是很快很简单的,不到半天就能搭好小车了......
主要部件:
主控: 树莓派4B 4G
电机: MG310 13线霍尔编码器 减速比 1:20 ( 4个 ) 购于 轮趣科技 淘宝店
电机控制板:幻尔 IIC四路电机扩展板 购于幻尔科技淘宝店
车轮: 购于 金色传说 淘宝店 (2.5mm轴)这个轮子摩擦力可以,价格还便宜!
车架: 使用 购于 星呗机器人淘宝店 的车架,贵~~
屏幕: 7英寸 HDML 显示屏,二手咸鱼购入
摄像头: 普通USB摄像头 (一般使用640*480像素模式),随便来个上网课的摄像头都行!
其余部件: 降压模块、6000mah电池、DC电池开关......
部分模块展示:
1、幻尔IIC四路电机控制板:
小车运动控制代码:
树莓派通过IIC与电机控制板通信,使电机控制板发PWM信号驱动电机运转:
这里我在Motor_control.py文件中加入了一些获取键盘值、字典的操作来简单控制小车
但在程序上获取键盘值每次都需要按一次回车,比较不方便......
Motor_control.py
这部分是电机控制代码:包含一些正反转,左右原地旋转的基本逻辑,这是为开环控制写的,因此四个轮子速度设定都一样,
import smbus
import time
import struct
# 设置I2C总线号,通常为1
I2C_BUS = 1
# 设置四路电机驱动模块的I2C地址
MOTOR_ADDR = 0x34
# 寄存器地址
ADC_BAT_ADDR = 0x00
MOTOR_TYPE_ADDR = 0x14 # 编码电机类型设置
MOTOR_ENCODER_POLARITY_ADDR = 0x15 # 设置编码方向极性,
# 如果发现电机转速根本不受控制,要么最快速度转动,要么停止。可以将此地址的值重新设置一下
# 范围0或1,默认0
MOTOR_FIXED_PWM_ADDR = 0x1F # 固定PWM控制,属于开环控制,范围(-100~100)
MOTOR_FIXED_SPEED_ADDR = 0x33 # 固定转速控制,属于闭环控制,
# 单位:脉冲数每10毫秒,范围(根据具体的编码电机来,受编码线数,电压大小,负载大小等影响,一般在±50左右)
MOTOR_ENCODER_TOTAL_ADDR = 0x3C # 4个编码电机各自的总脉冲值
# #如果已知电机每转一圈的脉冲数为U,又已知轮子的直径D,那么就可以通过脉冲计数的方式得知每个轮子行进的距离
# #比如读到电机1的脉冲总数为P,那么行进的距离为(P/U) * (3.14159*D)
# #对于不同的电机可以自行测试每圈的脉冲数U,可以手动旋转10圈读出脉冲数,然后取平均值得出
# 电机类型具体值
MOTOR_TYPE_WITHOUT_ENCODER = 0
MOTOR_TYPE_TT = 1
MOTOR_TYPE_N20 = 2 #MG310与N20相同
MOTOR_TYPE_JGB37_520_12V_110RPM = 3 # 磁环每转是44个脉冲 减速比:90 默认
# 电机类型及编码方向极性
MotorType = MOTOR_TYPE_N20
MotorEncoderPolarity = 1
bus = smbus.SMBus(I2C_BUS)
speed1 = [50, 50, 50, 50]
speed2 = [-50, -50, -50, -50]
speed3 = [0, 0, 0, 0]
speed4 = [-50, 50, 50, -50]
speed5 = [0, 0, 0, 0]
new_speed = 50
pwm1 = [50, 50, 50, 50]
pwm2 = [-100, -100, -100, -100]
pwm3 = [0, 0, 0, 0]
def Motor_Init(): # 电机初始化
bus.write_byte_data(MOTOR_ADDR, MOTOR_TYPE_ADDR, MotorType) # 设置电机类型
time.sleep(0.5)
bus.write_byte_data(MOTOR_ADDR, MOTOR_ENCODER_POLARITY_ADDR, MotorEncoderPolarity) # 设置编码极性
# 控制电机向前的代码
def move_forward():
print("向前移动")
global new_speed, speed5
speed5[0] = new_speed*(-1)
speed5[1] = new_speed
speed5[2] = new_speed
speed5[3] = new_speed*(-1)
bus.write_i2c_block_data(MOTOR_ADDR, MOTOR_FIXED_SPEED_ADDR, speed5)
# 控制电机向后的代码
def move_backward():
print("向后移动")
global new_speed, speed5
speed5[0] = new_speed
speed5[1] = new_speed*(-1)
speed5[2] = new_speed*(-1)
speed5[3] = new_speed
bus.write_i2c_block_data(MOTOR_ADDR, MOTOR_FIXED_SPEED_ADDR, speed5)
# 控制电机向左的代码
def move_left():
print("向左移动")
global