二维舵机颜色追踪,使用树莓派+opencv+usb摄像头+两个舵机实现颜色追踪,采用pid调控

效果演示

二维云台颜色追踪

使用树莓派+opencv+usb摄像头+两个舵机实现颜色追踪,采用pid调控

import cv2
import time
import numpy as np
from threading import Thread
from servo import Servo
from pid import PID# 初始化伺服电机
pan = Servo(pin=19)
tilt = Servo(pin=16)
panAngle = 0
tiltAngle = 0
pan.set_angle(panAngle)
tilt.set_angle(tiltAngle)# 定义视频流类
class VideoStream:def __init__(self, src=0):self.stream = cv2.VideoCapture(src)self.stream.set(cv2.CAP_PROP_FRAME_WIDTH, 320)self.stream.set(cv2.CAP_PROP_FRAME_HEIGHT, 240)self.stream.set(cv2.CAP_PROP_FPS, 30)self.grabbed, self.frame = self.stream.read()self.stopped = Falsedef start(self):Thread(target=self.update, args=()).start()return selfdef update(self):while not self.stopped:self.grabbed, self.frame = self.stream.read()def read(self):return self.framedef stop(self):self.stopped = Trueself.stream.release()# 启动视频流
vs = VideoStream(src=0).start()# 设置 PID 控制器参数
pan_pid = PID(0.05, 0.01, 0.001)
tilt_pid = PID(0.05, 0.01, 0.001)
pan_pid.initialize()
tilt_pid.initialize()# 计算帧率
fps = 0
pos = (10, 20)
font = cv2.FONT_HERSHEY_SIMPLEX
height = 0.5
weight = 1
myColor = (0, 0, 255)def nothing(x):passcv2.namedWindow('PID Tuner')
cv2.createTrackbar('Pan Kp', 'PID Tuner', int(pan_pid.kP * 100), 100, nothing)
cv2.createTrackbar('Pan Ki', 'PID Tuner', int(pan_pid.kI * 100), 100, nothing)
cv2.createTrackbar('Pan Kd', 'PID Tuner', int(pan_pid.kD * 100), 100, nothing)
cv2.createTrackbar('Tilt Kp', 'PID Tuner', int(tilt_pid.kP * 100), 100, nothing)
cv2.createTrackbar('Tilt Ki', 'PID Tuner', int(tilt_pid.kI * 100), 100, nothing)
cv2.createTrackbar('Tilt Kd', 'PID Tuner', int(tilt_pid.kD * 100), 100, nothing)last_update = time.time()
update_interval = 0.1  # 控制更新频率try:while True:tStart = time.time()frame = vs.read()if frame is None:print("Failed to grab frame")breakframe = cv2.flip(frame, 1)frameHSV = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)cv2.putText(frame, str(int(fps)) + ' FPS', pos, font, height, myColor, weight)lowerBound = np.array([0, 147, 114])upperBound = np.array([88, 255, 255])myMask = cv2.inRange(frameHSV, lowerBound, upperBound)contours, _ = cv2.findContours(myMask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)if len(contours) > 0:contours = sorted(contours, key=lambda x: cv2.contourArea(x), reverse=True)contour = contours[0]x, y, w, h = cv2.boundingRect(contour)cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 0, 255), 3)# 计算误差errorX = (x + w / 2) - (320 / 2)errorY = (240 / 2) - (y + h / 2)  # 反转误差方向if time.time() - last_update > update_interval:# 获取PID参数并更新pan_pid.kP = cv2.getTrackbarPos('Pan Kp', 'PID Tuner') / 100pan_pid.kI = cv2.getTrackbarPos('Pan Ki', 'PID Tuner') / 100pan_pid.kD = cv2.getTrackbarPos('Pan Kd', 'PID Tuner') / 100tilt_pid.kP = cv2.getTrackbarPos('Tilt Kp', 'PID Tuner') / 100tilt_pid.kI = cv2.getTrackbarPos('Tilt Ki', 'PID Tuner') / 100tilt_pid.kD = cv2.getTrackbarPos('Tilt Kd', 'PID Tuner') / 100panAdjustment = pan_pid.update(errorX, sleep=0)tiltAdjustment = tilt_pid.update(errorY, sleep=0)panAngle += panAdjustmenttiltAngle += tiltAdjustment# 限制角度范围panAngle = max(-90, min(panAngle, 120))tiltAngle = max(-90, min(tiltAngle, 90))# 设置伺服电机角度pan.set_angle(panAngle)tilt.set_angle(tiltAngle)last_update = time.time()# 仅在图形环境中显示图像窗口try:cv2.imshow('Camera', frame)cv2.imshow('Mask', myMask)except cv2.error as e:print(f"OpenCV error: {e}")if cv2.waitKey(1) == ord('q'):breaktEnd = time.time()loopTime = tEnd - tStartfps = .9 * fps + .1 * (1 / loopTime)finally:vs.stop()cv2.destroyAllWindows()

在相同文件路径下创建一个名为pid.py的文件

# pid.py
# -*- coding: UTF-8 -*-
# 调用必需库
import timeclass PID:def __init__(self, kP=1, kI=0, kD=0):# 初始化参数self.kP = kPself.kI = kIself.kD = kDdef initialize(self):# 初始化当前时间和上一次计算的时间self.currTime = time.time()self.prevTime = self.currTime# 初始化上一次计算的误差self.prevError = 0# 初始化误差的比例值,积分值和微分值self.cP = 0self.cI = 0self.cD = 0def update(self, error, sleep=0.2):# 暂停time.sleep(sleep)# 获取当前时间并计算时间差self.currTime = time.time()deltaTime = self.currTime - self.prevTime# 计算误差的微分deltaError = error - self.prevError# 比例项self.cP = error# 积分项self.cI += error * deltaTime# 微分项self.cD = (deltaError / deltaTime) if deltaTime > 0 else 0# 保存时间和误差为下次更新做准备self.prevTime = self.currTimeself.prevError = error# 返回输出值return sum([self.kP * self.cP,self.kI * self.cI,self.kD * self.cD])def set_Kp(self, kP):self.kP = kPdef set_Ki(self, kI):self.kI = kIdef set_Kd(self, kD):self.kD = kD

在相同文件路径下创建一个名为servo.py的文件

import pigpio
from time import sleep
import subprocess# Start the pigpiod daemon
result = None
status = 1
for x in range(3):p = subprocess.Popen('sudo pigpiod', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)result = p.stdout.read().decode('utf-8')status = p.poll()if status == 0:breaksleep(0.2)
if status != 0:print(status, result)class Servo():MAX_PW = 1250  # 0.5/20*100MIN_PW = 250   # 2.5/20*100_freq = 50     # 50 Hz, 20msdef __init__(self, pin, min_angle=-90, max_angle=90):self.pi = pigpio.pi()self.pin = pinself.pi.set_PWM_frequency(self.pin, self._freq)self.pi.set_PWM_range(self.pin, 10000)self.angle = 0self.max_angle = max_angleself.min_angle = min_angleself.pi.set_PWM_dutycycle(self.pin, 0)def set_angle(self, angle):if angle > self.max_angle:angle = self.max_angleelif angle < self.min_angle:angle = self.min_angleself.angle = angleduty = self.map(angle, -90, 90, 250, 1250)self.pi.set_PWM_dutycycle(self.pin, duty)def get_angle(self):return self.angledef stop(self):self.pi.set_PWM_dutycycle(self.pin, 0)self.pi.stop()def map(self, x, in_min, in_max, out_min, out_max):return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_minif __name__ == '__main__':pan = Servo(pin=13, max_angle=90, min_angle=-90)tilt = Servo(pin=12, max_angle=30, min_angle=-90)panAngle = 0tiltAngle = 0pan.set_angle(panAngle)tilt.set_angle(tiltAngle)sleep(1)while True:for angle in range(0, 90, 1):pan.set_angle(angle)tilt.set_angle(angle)sleep(.01)sleep(.5)for angle in range(90, -90, -1):pan.set_angle(angle)tilt.set_angle(angle)sleep(.01)sleep(.5)for angle in range(-90, 0, 1):pan.set_angle(angle)tilt.set_angle(angle)sleep(.01)sleep(.5)

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

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

相关文章

【抽代复习笔记】26-群(二十):子群的定义以及第一、第二判定定理

子群 定义1&#xff1a;(G,o)是一个群&#xff0c;H是G的非空子集&#xff0c;若H关于G的乘法o也能作成群&#xff08;满足群的判定定理&#xff1a;封闭性、结合律、单位元、逆元&#xff09;&#xff0c;则称H为G的子群&#xff0c;记作H ≤ G&#xff1b;若H是G的真子集&am…

【启明智显分享】手持遥控器HMI解决方案:2.8寸触摸串口屏助力实现智能化

现代生活不少家居不断智能化&#xff0c;但是遥控器却并没有随之升级。在遥控交互上&#xff0c;传统遥控器明显功能不足&#xff1a;特别是大屏智能电视&#xff0c;其功能主要由各种APP程序实现。在电脑上鼠标轻轻点击、在手机上触摸屏丝滑滑动&#xff0c;但是在电视上这些A…

SpringBoot 启动流程二

SpringBoot启动流程二 我们首先查看构造方法 SpringApplication 我们发现这个构造方法还是在SpringApplication类里面 这个构造方法还是调用了自身的构造方法 传入了两个参数 第一个参数叫resourceLoader 传入的是一个资源加载器 要从外部读入东西 这个方法通过this关键字…

c++纵横字谜

1.实现一个纵横字谜 2.支持14x14的网格 3.可以查看答案 4.猜测错误会提示答案信息 5.从txt读取词汇 6.每次游戏开始 随机生成纵横字谜 n’h

leetcode216.组合总和III、40.组合总和II、39.组合总和

216.组合总和III 找出所有相加之和为 n 的 k 个数的组合&#xff0c;且满足下列条件&#xff1a; 只使用数字1到9 每个数字 最多使用一次 返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次&#xff0c;组合可以以任何顺序返回。 示例 1: 输入: k 3, n 7 输出…

deepin UOS AI 如何配置自定义模型

科技飞速发展的今天&#xff0c;操作系统作为计算机系统的灵魂&#xff0c;其每一次的更新与变革都牵动着无数用户的心弦。近日&#xff0c;开源操作系统 deepin 迎来了一次重大更新&#xff0c;这次更新不仅在性能上进行了全面优化&#xff0c;更在 AI 智能化方面迈出了划时代…

git 常用语句

git 常用语句 git init #使用当前目录初始化为git仓库 git init #使用指定目录作为git仓库 git init newrepogit clone #从远程仓库将仓库拷贝到当前目录 #格式 git clone <repo> #示例 git clone git://github.com/schacon/grit.git#从远程仓库拷贝项目到指定目录 #格…

人工智能标准化与AI科技快速进步的矛盾

人工智能标准化与技术快速进步之间确实存在一定的矛盾&#xff0c;这主要体现在以下几个方面&#xff1a; 快速发展的技术与标准化的稳定性。人工智能技术以其快速的创新和进步而闻名。新的算法、模型和应用不断涌现&#xff0c;但标准化过程需要时间和广泛的共识&#xff0c;这…

【解决方案】笔记本电脑屏幕亮度调节失效(Dell G15 5510 使用Fn调节)

目前解决方案&#xff1a;使用驱动总裁&#xff08;其他的驱动安装软件应该也可以&#xff0c;个人觉得这个好用&#xff09;&#xff0c;更新显卡驱动即可。如图所示本人更新了Intel UHD Graphics核显驱动&#xff0c;功能回复正常。 使用Fn快捷键调节亮度如图所示&#xff0…

项目页面优化,我们该怎么做呢?

避免页面卡顿 怎么衡量页面卡顿的情况呢&#xff1f; 失帧和帧率FPS 60Hz就是帧率fps&#xff0c;即一秒钟60帧&#xff0c;换句话说&#xff0c;一秒钟的动画是由60幅静态图片连在一起形成的。 卡了&#xff0c;失帧了&#xff0c;或者掉帧了&#xff0c;一秒钟没有60个画面&…

Java中的软件架构重构与升级策略

Java中的软件架构重构与升级策略 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 重构与升级的背景和意义 软件架构在应用开发中起着至关重要的作用。随着技术…

ARIES,数据恢复算法,万变不离其宗...

今天来聊两个问题&#xff1a; 1. 如果缓冲池&#xff08;buffer pool&#xff09;满了&#xff0c;哪些数据页&#xff08;page&#xff09;要刷盘&#xff0c;哪些数据页不刷盘&#xff1f; 2. 数据库崩了&#xff0c;怎么利用检查点&#xff08;checkpoint&#xff09;与预写…

浅谈http协议及常见的面试题

1、浅谈http协议 HTTP&#xff08;Hypertext Transfer Protocol&#xff09;超文本传输协议&#xff0c;是互联网上应用最为广泛的一种网络协议&#xff0c;所有的WWW文件都必须遵守这个标准。它是基于TCP/IP通信协议来传递数据&#xff08;HTML文件、图片文件、查询结果等&am…

Django 定义模型执行迁移

1&#xff0c;创建应用 Test/app8 python manage.py startapp app8 2&#xff0c;注册应用 Test/Test/settings.py 3&#xff0c;配置路由 Test/Test/urls.py from django.contrib import admin from django.urls import path, includeurlpatterns [path(app8/, include(a…

g++和 gcc 编译入门教程

GNU GNU 编译器集合&#xff08;GNU Compiler Collection&#xff0c;简称 GCC&#xff09;是一个由自由软件基金会&#xff08;Free Software Foundation&#xff0c;简称 FSF&#xff09;开发的编译器系统&#xff0c;它是 GNU 项目的一部分。GCC 支持多种编程语言&#xff…

硅纪元视角 | AI纳米机器人突破癌症治疗,精准打击肿瘤细胞

在数字化浪潮的推动下&#xff0c;人工智能&#xff08;AI&#xff09;正成为塑造未来的关键力量。硅纪元视角栏目紧跟AI科技的最新发展&#xff0c;捕捉行业动态&#xff1b;提供深入的新闻解读&#xff0c;助您洞悉技术背后的逻辑&#xff1b;汇聚行业专家的见解&#xff0c;…

Ubuntu24.04之安装KVM(二百五十五)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

QT+OpenCV在Android上实现人脸实时检测与目标检测

一、功能介绍 在当今的移动应用领域&#xff0c;随着技术的飞速发展和智能设备的普及&#xff0c;将先进的计算机视觉技术集成到移动平台&#xff0c;特别是Android系统中&#xff0c;已成为提升用户体验、拓展应用功能的关键。其中&#xff0c;目标检测与人脸识别作为计算机视…

mindspore打开第十四天文本解码原理1

## __文本解码原理\-\-以MindNLP为例__ ### 回顾&#xff1a;自回归语言模型 __根据前文预测下一个单词__ <div aligncenter><img src"https://openi.pcl.ac.cn/mindspore-courses/Step_into_LLMs/raw/commit/8f6e55c907ef7d2b616e8e3c4da76b065633c2ae/Season…

vue3 hooks el-table封装 (未使用ts版本)

基于elementuiPlus el-table 表格 import { ref, reactive, onMounted } from vue import { ElMessage, ElMessageBox, ElNotification } from element-plus /*** FileDescription: el-table 函数式组件hooks,* function:useTable(config)* param {object} config useTable(配置…