视觉循迹小车(旭日x3派、摄像头、循迹)

2024-03-28 00:36

本文主要是介绍视觉循迹小车(旭日x3派、摄像头、循迹),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1、旭日x3派(烧录好系统镜像)

2、USB摄像头

3、TB6612

4、小车底盘(直流电机或直流减速电机)

 

视觉循迹原理

x3派读取摄像头图像,转换成灰度图像,从灰度图像中选择第 120 行(图像的一个水平线),遍历第120行的全部320列,根据像素值小于或大于阈值,将相应的值(0 或 1)添加到 date 列表中。最后根据小于阈值的像素个数和它们的总和来判断黑色赛道的位置,以此调节左右电机的转速实现循迹。

 

python代码

import Hobot.GPIO as GPIO

import time

import cv2

 

class EYE():

    def __init__(self):

        self.video = cv2.VideoCapture(8)  #打开索引为8的摄像头

        ret = self.video.isOpened()  #判断摄像头是否打开成功

        if ret:

            print("The video is opened.")

        else:

            print("No video.")

 

        codec = cv2.VideoWriter_fourcc( 'M', 'J', 'P', 'G' )   #设置参数

        self.video.set(cv2.CAP_PROP_FOURCC, codec)

        self.video.set(cv2.CAP_PROP_FPS, 30)

        self.video.set(cv2.CAP_PROP_FRAME_WIDTH, 672)

        self.video.set(cv2.CAP_PROP_FRAME_HEIGHT, 672)

 

        # 创建全屏窗口

        #cv2.namedWindow("Camera Feed", cv2.WND_PROP_FULLSCREEN)

        #cv2.setWindowProperty("Camera Feed", cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)

 

    def outmiss(self):

        _, img = self.video.read()  #从摄像头读取一帧图像

        img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  #将图像转为灰度

        img = img[120]   #选择图像的第120行,一共240行。

 

        date = []

        for i in range(320):    #遍历每一列,一共320列

            if img[i] <= 64:   #如果当前列的像素值小于等于 64,将 1 添加到 date 列表,表示该像素是感兴趣的。

                date.append(1)

            elif img[i] > 64:  #如果当前列的像素值大于 64,将 0 添加到 date 列表,表示该像素不感兴趣。

                date.append(0)

 

        n = 0   #用于计算感兴趣的像素数量。  

        sum = 0   #用于计算感兴趣像素的列索引总和。

        for i in range(320):

            if date[i] == 1:

                sum += i   #如果该列的像素是感兴趣的(即 date[i] 为 1),则更新 sum 和 n。

                n += 1

        if n >= 18:

            return sum / n - 159.5

        else:

            return None

 

    def off(self):

 

        self.video.release()

 

class CTRL():

    def __init__(self, in1, in2, in3, in4, pa, pb):

        GPIO.setmode(GPIO.BOARD)

        GPIO.setwarnings(False)

 

        GPIO.setup(in1, GPIO.OUT)

        GPIO.setup(in2, GPIO.OUT)

        GPIO.setup(in3, GPIO.OUT)

        GPIO.setup(in4, GPIO.OUT)

 

        self.in1 = in1

        self.in2 = in2

        self.in3 = in3

        self.in4 = in4

 

        self.PWMA = GPIO.PWM(pa, 48000)

        self.PWMB = GPIO.PWM(pb, 48000)

 

    def drive(self, FL, FR):

        if FL >= 0:

            GPIO.output(self.in3, GPIO.HIGH)

            GPIO.output(self.in4, GPIO.LOW)

        elif FL < 0:

            GPIO.output(self.in4, GPIO.HIGH)

            GPIO.output(self.in3, GPIO.LOW)

 

        if FR >= 0:

            GPIO.output(self.in1, GPIO.HIGH)

            GPIO.output(self.in2, GPIO.LOW)

        elif FR < 0:

            GPIO.output(self.in2, GPIO.HIGH)

            GPIO.output(self.in1, GPIO.LOW)

 

        self.PWMA.ChangeDutyCycle(abs(FR))

        self.PWMB.ChangeDutyCycle(abs(FL))

        self.PWMA.start(abs(FR))

        self.PWMB.start(abs(FL))

 

    def stop(self):

        GPIO.output(self.in1, GPIO.LOW)

        GPIO.output(self.in2, GPIO.LOW)

        GPIO.output(self.in3, GPIO.LOW)

        GPIO.output(self.in4, GPIO.LOW)

 

        self.PWMA.ChangeDutyCycle(0)

        self.PWMB.ChangeDutyCycle(0)

        self.PWMA.start(0)

        self.PWMB.start(0)

 

    def clean(self):

        self.PWMB.stop()

        self.PWMA.stop()

        GPIO.cleanup()

        

class PID():

    def __init__(self,KP,KI,KD):

        self.KP = KP

        self.KI = KI

        self.KD = KD

        self.p1 , self.p2 = 0 , 0#保留一个帧的误差

        self.i = 0#积累误差初值

        

    def naosu(self,miss):

        if miss != None:

            self.p1 , self.p2 = self.p2 , miss #替换缓存的误差

            self.i += miss

            if self.i > 1000:

                self.i -= 800

            if self.i < -1000:

                self.i += 800#积累误差的限制

            naosu = self.KP * miss + self.KI * self.i + self.KD * (self.p2 - self.p1)

            #按照公式输出

            return naosu

            

        elif miss == None:

        #摄像头读空时,根据上一帧的缓存误差正负,来判断现在应该原地左转还是右转

            if self.p2 >= 0:

                self.p1 , self.p2 = self.p2 , 1

                return "r"

                

            elif self.p2 < 0:

                self.p1 , self.p2 = self.p2 , -1

                return "l"

 

if __name__ == '__main__':

    try:

        Ctrl = CTRL(11, 13, 16, 15, 32, 33)  # 设置管脚

        Eye = EYE()  # 调用视觉模块

        Pid = PID(0.095,0.001,0.52)#调用PID,传入参数

        Ctrl.drive(25, 25)  # 小车的始发运动

        time.sleep(0.5)

        while True:

            ms = Eye.outmiss()  # 获取误差

            ns = Pid.naosu(ms)#获取修正值

            if ns == "r":#原地转弯的情况

                Ctrl.drive(20,-20)

            elif ns == "l":

                Ctrl.drive(-20,20)

            else:#限制修正值,保证不超过PWM上下限

                if ns > 18:

                    ns = 18

                if ns < -18:

                    ns = -18

                    

                Ctrl.drive(25+ns, 25-ns)  # 小车的始发运动

         

            # 添加代码来显示摄像头捕获的图像

            _, frame = Eye.video.read()

            cv2.imshow("Camera Feed", frame)

            time.sleep(0.2)

            if cv2.waitKey(1) & 0xFF == ord('q'):

                break

                

                

    finally:

        Ctrl.stop()

        Ctrl.clean()

        Eye.off()

        cv2.destroyAllWindows()

这篇关于视觉循迹小车(旭日x3派、摄像头、循迹)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/853912

相关文章

基于UE5和ROS2的激光雷达+深度RGBD相机小车的仿真指南(五):Blender锥桶建模

前言 本系列教程旨在使用UE5配置一个具备激光雷达+深度摄像机的仿真小车,并使用通过跨平台的方式进行ROS2和UE5仿真的通讯,达到小车自主导航的目的。本教程默认有ROS2导航及其gazebo仿真相关方面基础,Nav2相关的学习教程可以参考本人的其他博客Nav2代价地图实现和原理–Nav2源码解读之CostMap2D(上)-CSDN博客往期教程: 第一期:基于UE5和ROS2的激光雷达+深度RG

计算机视觉工程师所需的基本技能

一、编程技能 熟练掌握编程语言 Python:在计算机视觉领域广泛应用,有丰富的库如 OpenCV、TensorFlow、PyTorch 等,方便进行算法实现和模型开发。 C++:运行效率高,适用于对性能要求严格的计算机视觉应用。 数据结构与算法 掌握常见的数据结构(如数组、链表、栈、队列、树、图等)和算法(如排序、搜索、动态规划等),能够优化代码性能,提高算法效率。 二、数学基础

《计算机视觉工程师养成计划》 ·数字图像处理·数字图像处理特征·概述~

1 定义         从哲学角度看:特征是从事物当中抽象出来用于区别其他类别事物的属性集合,图像特征则是从图像中抽取出来用于区别其他类别图像的属性集合。         从获取方式看:图像特征是通过对图像进行测量或借助算法计算得到的一组表达特性集合的向量。 2 认识         有些特征是视觉直观感受到的自然特征,例如亮度、边缘轮廓、纹理、色彩等。         有些特征需要通

【python计算机视觉编程——7.图像搜索】

python计算机视觉编程——7.图像搜索 7.图像搜索7.1 基于内容的图像检索(CBIR)从文本挖掘中获取灵感——矢量空间模型(BOW表示模型)7.2 视觉单词**思想****特征提取**: 创建词汇7.3 图像索引7.3.1 建立数据库7.3.2 添加图像 7.4 在数据库中搜索图像7.4.1 利用索引获取获选图像7.4.2 用一幅图像进行查询7.4.3 确定对比基准并绘制结果 7.

参会邀请 | 第二届机器视觉、图像处理与影像技术国际会议(MVIPIT 2024)

第二届机器视觉、图像处理与影像技术国际会议(MVIPIT 2024)将于2024年9月13日-15日在中国张家口召开。 MVIPIT 2024聚焦机器视觉、图像处理与影像技术,旨在为专家、学者和研究人员提供一个国际平台,分享研究成果,讨论问题和挑战,探索前沿技术。诚邀高校、科研院所、企业等有关方面的专家学者参加会议。 9月13日(周五):签到日 9月14日(周六):会议日 9月15日(周日

【python计算机视觉编程——8.图像内容分类】

python计算机视觉编程——8.图像内容分类 8.图像内容分类8.1 K邻近分类法(KNN)8.1.1 一个简单的二维示例8.1.2 用稠密SIFT作为图像特征8.1.3 图像分类:手势识别 8.2贝叶斯分类器用PCA降维 8.3 支持向量机8.3.2 再论手势识别 8.4 光学字符识别8.4.2 选取特征8.4.3 多类支持向量机8.4.4 提取单元格并识别字符8.4.5 图像校正

4-4.Andorid Camera 之简化编码模板(获取摄像头 ID、选择最优预览尺寸)

一、Camera 简化思路 在 Camera 的开发中,其实我们通常只关注打开相机、图像预览和关闭相机,其他的步骤我们不应该花费太多的精力 为此,应该提供一个工具类,它有处理相机的一些基本工具方法,包括获取摄像头 ID、选择最优预览尺寸以及打印相机参数信息 二、Camera 工具类 CameraIdResult.java public class CameraIdResult {

基于微信小程序与嵌入式系统的智能小车开发(详细流程)

一、项目概述 本项目旨在开发一款智能小车,结合微信小程序与嵌入式系统,提供实时图像处理与控制功能。用户可以通过微信小程序远程操控小车,并实时接收摄像头采集的图像。该项目解决了传统遥控小车在图像反馈和控制延迟方面的问题,提升了小车的智能化水平,适用于教育、科研和娱乐等多个领域。 二、系统架构 1. 系统架构设计 本项目的系统架构主要分为以下几个部分: 微信小程序:负责用户界面、控制指令的

Python计算机视觉编程 第十章

目录 一、OpenCv基础知识 1.读取和写入图像 2.颜色空间 3.显示图像和结果 二、处理视频 1.输入视频 2.将视频读取到NumPy数组中 三、跟踪 1.光流 2.Lucas-Kanade算法 一、OpenCv基础知识 OpenCV 自带读取、写入图像函数以及矩阵操作和数学库。 1.读取和写入图像 import cv2# 读取图像im = c

用了虚拟机后,本机摄像头打不开了(联想电脑thinkpad)

虚拟机有摄像头,我断开了连接,现在本机的摄像头打开就是一个锁 我先把虚拟机的摄像头关了 然后把本机的vm usb关闭了 Win+R),输入services.msc,找到VMware USB Arbitration Service,确保其状态为“关闭 然后打开桌面助手 开启 参考: 联想知识库