如何选择大良网站建设,做网站 域名如何要回,一级a做爰片在线网站,亚洲影视传媒有限公司基于旭日x3派的视觉循迹小车#xff0c;未完全实现#xff0c;参考#xff1a;https://developer.horizon.cc/forumDetail/146176819622746404 效果硬件视觉循迹原理python代码 效果 硬件
1、旭日x3派#xff08;烧录好系统镜像#xff09; 2、USB摄像头 3、TB6612 4、小… 基于旭日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 relif self.p2 0:self.p1 , self.p2 self.p2 , -1return lif __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(25ns, 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()