视觉循迹小车(旭日x3派、opencv)

基于旭日x3派的视觉循迹小车,未完全实现,参考:https://developer.horizon.cc/forumDetail/146176819622746404

    • 效果
    • 硬件
    • 视觉循迹原理
    • python代码

效果

硬件

1、旭日x3派(烧录好系统镜像)
2、USB摄像头
3、TB6612
4、小车底盘(直流电机或直流减速电机)

视觉循迹原理

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

python代码

import Hobot.GPIO as GPIO
import time
import cv2class 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 += 1if n >= 18:return sum / n - 159.5else:return Nonedef 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 = in1self.in2 = in2self.in3 = in3self.in4 = in4self.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 = KPself.KI = KIself.KD = KDself.p1 , self.p2 = 0 , 0#保留一个帧的误差self.i = 0#积累误差初值def naosu(self,miss):if miss != None:self.p1 , self.p2 = self.p2 , miss #替换缓存的误差self.i += missif self.i > 1000:self.i -= 800if self.i < -1000:self.i += 800#积累误差的限制naosu = self.KP * miss + self.KI * self.i + self.KD * (self.p2 - self.p1)#按照公式输出return naosuelif miss == None:#摄像头读空时,根据上一帧的缓存误差正负,来判断现在应该原地左转还是右转if self.p2 >= 0:self.p1 , self.p2 = self.p2 , 1return "r"elif self.p2 < 0:self.p1 , self.p2 = self.p2 , -1return "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 = 18if ns < -18:ns = -18Ctrl.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'):breakfinally:Ctrl.stop()Ctrl.clean()Eye.off()cv2.destroyAllWindows()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/799254.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++ //练习 11.29 如果给定的关键字不在容器中,upper_bound、lower_bound和equal_range分别会返回什么?

C Primer&#xff08;第5版&#xff09; 练习 11.29 练习 11.29 如果给定的关键字不在容器中&#xff0c;upper_bound、lower_bound和equal_range分别会返回什么&#xff1f; 环境&#xff1a;Linux Ubuntu&#xff08;云服务器&#xff09; 工具&#xff1a;vim 解释 如果…

HashMap底层源码面试题

面试题1&#xff1a;HashMap是如何实现快速查找的&#xff1f; 答案&#xff1a; HashMap通过哈希表实现快速查找。它内部维护了一个数组&#xff08;称为桶数组或table&#xff09;&#xff0c;每个数组元素是一个链表或红黑树&#xff08;当链表长度超过一定阈值时&#xff…

摄像头校准漫反射板提高识别物体

摄像头校准漫反射板是一种用于摄像头校准的重要工具。在摄像头成像过程中&#xff0c;由于各种因素的影响&#xff0c;如光线、角度、镜头畸变等&#xff0c;会导致摄像头成像出现偏差。为了消除这些偏差&#xff0c;提高摄像头的成像质量&#xff0c;需要使用摄像头校准漫反射…

从头开发一个RISC-V的操作系统(四)嵌入式开发介绍

文章目录 前提嵌入式开发交叉编译GDB调试&#xff0c;QEMU&#xff0c;MAKEFILE练习 目标&#xff1a;通过这一个系列课程的学习&#xff0c;开发出一个简易的在RISC-V指令集架构上运行的操作系统。 前提 这个系列的大部分文章和知识来自于&#xff1a;[完结] 循序渐进&#x…

第十四讲:C语言字符函数和字符串函数

目录 1. 字符分类函数 2、字符转换函数 3. strlen的使⽤和模拟实现 4. strcpy 的使⽤和模拟实现 5. strcat 的使⽤和模拟实现 6. strcmp 的使⽤和模拟实现 7. strncpy 函数的使⽤ 8. strncat 函数的使⽤ 9. strncmp函数的使⽤ 10. strstr 的使⽤和模拟实现 11. strt…

[LeetCode][LCR186]文物朝代判断——贪心

题目 LCR 186. 文物朝代判断 展览馆展出来自 13 个朝代的文物&#xff0c;每排展柜展出 5 个文物。某排文物的摆放情况记录于数组 places&#xff0c;其中 places[i] 表示处于第 i 位文物的所属朝代编号。其中&#xff0c;编号为 0 的朝代表示未知朝代。请判断并返回这排文物的…

java开发职业发展和求职建议

在当今竞争激烈的就业市场中&#xff0c;Java开发职业的求职者需要具备一定的技能和知识&#xff0c;以在众多求职者中脱颖而出。以下是一些建议&#xff0c;帮助Java开发者提高自己的竞争力&#xff0c;找到理想的工作。 1. 掌握基本技能&#xff1a;首先&#xff0c;Java开发…

Vue中如何使用Ajax请求是通过第三方库axios或者原生的fetch API来实现的

在Vue中使用Ajax请求通常是通过第三方库&#xff0c;比如axios或者原生的fetch API来实现的。这里我将为你展示如何使用axios库在Vue中进行Ajax请求。 首先&#xff0c;你需要安装axios库。你可以通过npm或者yarn来安装&#xff1a; 使用npm: bash 复制 npm install axi…

mysql的索引类型与数据存储

mysql索引与类型 什么是索引&#xff1f; 索引&#xff08;Index&#xff09;是帮助MySQL高效获取数据的数据结构。我们可以简单理解为&#xff1a;快速查找排好序的一种数据结构。Mysql索引主要有两种结构&#xff1a;BTree索引和Hash索引。我们平常所说的索引&#xff0c;如…

校园圈子小程序,大学校园圈子,三段交付,源码交付,支持二开

介绍 在当今的数字化时代&#xff0c;校园社交媒体和在线论坛成为了学生交流思想、讨论问题以及分享信息的常用平台。特别是微信小程序&#xff0c;因其便捷性、用户基数庞大等特点&#xff0c;已逐渐成为构建校园社区不可或缺的一部分。以下是基于现有资料的校园小程序帖子发…

2024.4.1力扣每日一题——故障键盘

2024.4.1 题目来源我的题解方法一 直接利用StringBuilder的反转函数方法二 字符数组 题目来源 力扣每日一题&#xff1b;题序&#xff1a;2810 我的题解 方法一 直接利用StringBuilder的反转函数 使用StringBuilder构造结果&#xff0c;并利用其反转函数进行翻转 时间复杂度…

opencv如何寻找图片轮廓

在OpenCV中&#xff0c;寻找图片轮廓的基本步骤通常包括以下几个过程&#xff1a; 读取图片&#xff1a;首先&#xff0c;需要读取想要提取轮廓的图片。转换为灰度图&#xff1a;因为轮廓检测通常在灰度图上进行&#xff0c;所以需要将图片转换为灰度图。应用阈值或边缘检测&a…

(已解决)引入本地bootstrap无效,bootstrap和jquery的引入

问题&#xff1a; 首先我是跟着张天宇老师下载的bootstrap文件&#xff0c;新建了一个css文件夹&#xff0c;但是这样子<link rel"stylesheet" type"text/css" src"./css/bootstrap.css">在index.html引入没有用。 解决办法: 1.把建立的…

【opencv】示例-dft.cpp 该程序演示了离散傅立叶变换 (dft) 的使用,获取图像的 dft 并显示其功率谱...

#include "opencv2/core.hpp" // 包含OpenCV核心功能头文件 #include "opencv2/core/utility.hpp" // 包含OpenCV实用程序头文件 #include "opencv2/imgproc.hpp" // 包含OpenCV图像处理头文件 #include "opencv2/imgcodecs.hpp" // 包…

CSS 学习笔记 总结

CSS 布局方式 • 表格布局 • 元素定位 • 浮动布局&#xff08;注意浮动的负效应&#xff09; • flex布局 • grid布局&#xff08;感兴趣的可以看下菜鸟教程&#xff09; 居中设置 元素水平居中 • 设置宽度后&#xff0c;margin设置为auto • 父容器设置text-alig…

积木报表Excel数据量大导出慢导不出问题、大量数据导不出问题优化方案和分析解决思路(优化前一万多导出失败,优化后支持百万级跨库表导出)

文章目录 积木报表Excel数据量大导出慢导不出问题、大量数据导不出问题优化方案和分析解决思路&#xff08;优化前一万多导出失败&#xff0c;优化后支持百万级跨库表导出&#xff09;优化结果需求背景和解决方案的思考解决方案流程描述&#xff1a;关键代码引入easy excel新建…

Linux云计算之Linux基础3——Linux系统基础2

1、终端 终端(terminal)&#xff1a;人和系统交互的必要设备&#xff0c;人机交互最后一个界面&#xff08;包含独立的输入输出设备&#xff09; 物理终端(console)&#xff1a;直接接入本机器的键盘设备和显示器虚拟终端(tty)&#xff1a;通过软件方式虚拟实现的终端。它可以…

Docker 引擎离线安装包采集脚本

文章目录 一、场景说明二、脚本职责三、参数说明四、操作示例五、注意事项 一、场景说明 本自动化脚本旨在为提高研发、测试、运维快速部署应用环境而编写。 脚本遵循拿来即用的原则快速完成 CentOS 系统各应用环境部署工作。 统一研发、测试、生产环境的部署模式、部署结构、…

基于SSM的宠物管理系统

点击以下链接获取源码: https://download.csdn.net/download/qq_64505944/89076676?spm=1001.2014.3001.5503 技术:SSM(Spring+SpringMVC+MyBatis)+LayUI+Echarts技术栈,分页采用pagehelper插件,EasyExcel进行Excel文件的导入导出。 宠物管理系统 1 CHINER-宠物管理系…

opencv直方图

在OpenCV中&#xff0c;直方图是一个重要的图像分析工具&#xff0c;它可以提供关于图像亮度分布的详细信息。OpenCV提供了多种方法来计算和操作图像的直方图。 基本概念 直方图是一个离散函数&#xff0c;它将图像中的像素值映射到一个连续的区间上&#xff0c;并计算每个区…