树莓派笔记22_小车:小车电机开环运动与opencv摄像头巡线

  今日继续学习树莓派4B 4G:(Raspberry Pi,简称RPi或RasPi)

 本人所用树莓派4B 装载的系统与版本如下:

 版本可用命令 (lsb_release -a) 查询:

 Opencv 版本是4.5.1:

 Python 版本3.7.3:

今日尝试搭建一台小车,外观自行设计、树莓派主控、自行挑选模块 ,完成简单的巡线动作,就开环控制了,这篇文章的使用就不闭环了......

巡线的思想就是在视频屏幕最下方1/4的ROI区域灰度识别黑色色块,计算与中点的偏差,与中点偏差的像素过大就原地左右转调整,其余识别到黑线在偏差范围内不大时就正常走直线

自评:原地左右转以及没使用PID闭环使得这个视觉巡线小车看起来不太智能,还可改进>>>

文章提供测试代码讲解,整体代码贴出、测试效果图、完整测试工程下载

目录

小车外观与使用模块:

主要部件:

 部分模块展示:

小车运动控制代码:

Motor_control.py 

程序补足电机对向转动方向:

Opencv识别黑线:

Gray_find_black.py

测试效果截图:

Gray_find_black_roi.py

测试效果截图:

巡线代码:

Line_inspection.py

测试效果视频:

整体工程下载:

网上学习资料网址:


小车外观与使用模块:

搭个小车还是很快很简单的,不到半天就能搭好小车了......

主要部件:

主控:           树莓派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
### OpenCV 实现机器人或车辆的巡线算法 要实现基于 OpenCV 的机器人或车辆巡线功能,可以按照以下方法完成: #### 数据预处理 首先需要对摄像头捕获的图像进行必要的预处理。通常情况下,赛道的颜色可以通过 HSV 颜色空间中的特定范围来区分背景和其他物体[^4]。 ```python import cv2 import numpy as np def preprocess_image(image): hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) # 转换到HSV颜色空间 lower_black = np.array([0, 0, 0]) # 黑色下限 upper_black = np.array([180, 255, 30]) # 黑色上限 mask = cv2.inRange(hsv, lower_black, upper_black) # 创建掩码 return mask ``` #### 图像分割二值化 通过设定合适的阈值,将图像转化为黑白两部分,其中黑色代表赛道线条,白色代表其他区域。此过程有助于简化后续计算并提高效率。 ```python def threshold_image(mask): _, binary = cv2.threshold(mask, 1, 255, cv2.THRESH_BINARY) # 应用固定阈值 return binary ``` #### 扫描策略 对于二值化的图像,采用从底部中心向两侧扫描的方式寻找黑线位置。这种方法能够快速定位当前车道方向,并据此调整行驶路径。 ```python def find_line(binary_img, width=640, height=480): bottom_row = binary_img[height - 1, :] # 获取最下面一行像素 center_index = int(width / 2) # 向左扫描找第一个非零点 left_edge = None for i in range(center_index, 0, -1): if bottom_row[i]: left_edge = i break # 向右扫描找第一个非零点 right_edge = None for j in range(center_index, width): if bottom_row[j]: right_edge = j break return (left_edge, right_edge) ``` #### 控制逻辑 依据找到的边缘坐标决定转向角度或者速度差值,从而控制电机驱动轮子转动达到自动循迹目的[^2]。 ```python def control_vehicle(left_edge, right_edge, max_speed=100): if not left_edge and not right_edge: # 如果两边都找不到,则认为偏离轨道较大程度 turn_angle = 90 # 原地旋转直到重新发现线路为止 elif not left_edge or abs((right_edge-left_edge)/width*max_speed)>threshold_value: # 只有一侧可见时采取相应措施纠正偏差 pass else: mid_point=(left_edge+right_edge)//2 error=mid_point-width//2 kp=-0.5 #比例系数可以根据实际情况调节优化效果最佳 speed_difference=kp *error left_motor_speed=max_speed-speed_difference right_motor_speed=max_speed+speed_difference ``` 以上即为利用OpenCV库构建简单有效的视觉引导系统的核心流程概述[^1]^。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

NULL指向我

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值