首页 > 其他分享 >视觉循迹小车(旭日x3派、摄像头、循迹)

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

时间:2024-03-29 22:32:04浏览次数:22  
标签:旭日 __ 循迹 output self cv2 video GPIO 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()

标签:旭日,__,循迹,output,self,cv2,video,GPIO,x3
From: https://blog.csdn.net/m0_71523511/article/details/137092558

相关文章

  • 关于RDK X3(旭日X3派)的VPS不能输出300x300照片的临时解决办法参考
    探索工具使用JupyterNotebook逐句运行Python代码,并且可以通过matplotlib模块将nv12格式的图像直接在开发机的浏览器上显示。**如何为RDKX3安装JupyterNotebook:**https://developer.horizon.cc/forumDetail/188481611833243692**如何使用matplotlib将nv12的图像显示出......
  • NCV8702MX33TCG电源管理线性稳压器芯片中文资料PDF数据手册引脚图图片价格
    产品概述:NCV8702是一款200mA低漏静止电流、低漏线性稳压器,带超低噪声特性。它的低噪音结合高电源抑制比(PSRR)使其特别适用于射频、音频或成像应用。该器件采用先进的BiCMOS工艺制造,可提供低电流耗量和卓越噪声性能的强大组合。NCV8702可稳定使用小型低值1µ电容器......
  • NCV8703MX33TCG 线性稳压器芯片中文资料规格书PDF数据手册引脚图图片价格
    产品概述:NCV8703是一款低噪音、低功耗和低漏线性稳压器。该器件具有优异的噪音和PSRR规格,适用于使用射频接收器、成像传感器、音频处理器或需要外部洁净电源的任何部件的产品。NCV8703使用创新的自适应接地电流电路可确保轻负载调节下的超低接地电流。规格书参数:引脚图......
  • 关于使用MAX31865的注意事项
    在采购回的MAX31865模块需要自行焊接,包括插座和板子上的焊点。参考MAX31865和PT100PT1000的小白避坑攻略-CSDN博客 上面的避坑指南,对两线、三线、四线进行焊接说明。非常重要,否则读数不对,或者总是一个固定值。两线: 三线:四线:  具体的Arduino代码可参考:MAX31865RTDS......
  • 旭日x3派部署自己训练的模型(安全帽识别、视频流推理、yolov5-6.2)
    旭日x3派部署自己训练的模型(安全帽识别、视频流推理、yolov5-6.2)windows,框架pytorch,python3.7效果模型训练模型转换1、pt模型文件转onnx2、检查onnx模型3、准备校准数据4、onnx转bin上板视频流推理1、图片推理2、视频流推理效果模型训练进官网可克隆yolov5......
  • Angr-Learn-0x3
    Angr-Learn-0x3注意本文可以理解为官方文档的简单翻译+一部分个人理解符号执行与约束求解angr之所以强大并不因为它是一个模拟器,而是它能使用符号变量来执行。使用符号变量算术运算将产生一颗运算树(AST)。AST可以转换为SMT求解器的约束。使用位向量例子:#64-bitbitvectors......
  • python 使用PaddleOCR读取图片文字,并用pyttsx3转为音频
    python小白,纯纯小白,很久之前看了一遍菜鸟官网,但实在没有应用场景,所以过目即忘。最近工作不是很忙,给我出了个题目,觉得挺有意思,就玩一玩。  所以关键点就是,图片提取出文字,然后文字转音频。1.图片提取文字,PaddleOCR出题人士,给出了git上一个ocr的工具库,支持图文信息的抽取。用......
  • 8000MHz高频内存也赢不了AMD!锐龙7 7800X3D VS. i9-14900K网游与单机游戏性能对比
    一、前言:i9-14900K配8000MHz内存能否战胜锐龙77800X3D如今的Intel似乎有些魔怔,为了冲击高频而不顾一切。此前i9-14900K的满载功耗已经高达360W,而即将到来的i9-14900KS据闻峰值功耗已经超过400W,频率也来到了前所未有6.2GHz。与之形成强烈反差的是AMD的锐龙77800X3D,这款当前游戏......
  • 循迹小车驱动
    1.PWM2.USART3.GPIO4.ADC技术部分EXITHC_SR04中断定时器EXIT外部中断属于外设可监测GPIO口的电平信号触发方式上升下降双边PB7与PA7不能同时使用中断与AFIO有关中断引脚选择器只会选择其中一个中断暂停当前正在运行的程序。转而处理中断程序,处理完成后返回原来......
  • 旭日图
    案例1参考代码如下<!-- 此示例下载自https://echarts.apache.org/examples/zh/editor.html?c=sunburst-simple--><!DOCTYPEhtml><htmllang="en"style="height:100%"><head><metacharset="utf-8"></head......