基于Openmv的追小球的云台

介绍

在这篇文章,我会先介绍需要用到且需要注意的函数,之后再给出整体代码

在追小球的云台中,比较重要的部分就是云台(实质上就是舵机)的控制以及对识别的色块位置进行处理得到相应信息后控制云台进行运动

1、舵机模块和PID模块的导入

需要注意的是,PID还需要官方提供的PID文件(当然你要是把整体代码全部移植过来也是可以的)

from pyb import PID
from pyb import Servo

2、初始化舵机端口

这里初始化舵机端口,我的理解是就相当于一个宏定义

sp_servo=Servo(1)
cz_servo=Servo(2)

3、校准舵机,设置PWM信号的范围

sp_servo.calibration(500, 2500, 1500)
cz_servo.calibration(500, 2500, 1500)

这里的代码根据之前的初始化舵机端口名字来写,不同名不一样

这里用到的函数是

Servo.calibration([pulse_min,pulse_max,pulse_centre[,pulse_angle_90,pulse_speed_100]])

它后面的两个参数不需要用到,我们只对前三个参数进行说明

pulse_min:设置的最小脉冲宽度

pulse_max:设置的最大脉冲宽度

pulse_centre:中心(90度)\0度对应的位置

4、初始化PID控制器

PID控制器的初始化分为两种情况

情况1是在上机调试时的情况,情况2时在脱机运行时的情况

按道理来说,上机调试时由于数据的传输是需要时间的,也就是实时数据的获取存在延迟;而脱机运行时数据的传输更快,延迟更小

根据实时数据获取的延迟来看,在脱机运行时,由于数据传输的实时性很好,所以PID参数可以采用大一些的值;同理,在上机调试时,由于数据的实时性较差,所以采用更小的PID参数来进行调节

根据我上面的阐述,在设置PID参数时,脱机设置较大值,上机设置较小值;不知道是不是官方给出的代码出现了错误,它给出来的PID参数设置与我上述设置相反(我也不确定到底是谁错了)

 sp_pid = PID(p=0.1, i=0, imax=90)cz_pid = PID(p=0.1, i=0, imax=90)

5、判断最大色块

由于在进行小球的追踪时,肯定会有其他小球之外的色块存在,所以在这个时候,我们只对最大的色块进行处理(默认最大色块为小球)

def find_max(blobs):max_size = 0max_blob = Nonefor blob in blobs:if blob[2] * blob[3] > max_size:max_blob = blobmax_size = blob[2] * blob[3]return max_blob

对于判断最大色块,我们定义了一个函数find_max(blobs)来寻找最大色块

在这判断色块大小是根据色块查找函数find_blobs(thresholds)返回的blob对象列表的值来确定的

在Openmv官方例程和函数库中并没有给出blob对象的值,所以我们我们自己写一个色块寻找程序,并打印出blob对象的值

可以看到blob对象的值如下图所示 

所以blob[2]、[3]分别是blob对象的第3、4个参数,也就是色块的宽度和色块的高度,两个参数相乘即为色块的面积

6、误差的获取

通过用最大色块返回的中心坐标值减去图像中心坐标值,获得误差

sp_error = max_blob.cx() - img.width() / 2
cz_error = max_blob.cy() - img.height() / 2

7、误差的处理

 sp_output = sp_pid.get_pid(sp_error, 1) / 2cz_output = cz_pid.get_pid(cz_error, 1)sp_servo.angle(sp_servo.angle() + sp_output)cz_servo.angle(cz_servo.angle() - cz_output)

对误差的控制引入了PID的控制,在这里我就不对涉及pid.py文件的部分作说明,这两天会再写一篇文章对该文件及PID算法进行说明

8、main.py代码

import sensor,image,time
from pyb import PID
from pyb import Servo#初始化用于平移和倾斜的舵机(我的理解是这里就是做了一个宏定义)
sp_servo=Servo(1)
cz_servo=Servo(2)# 校准舵机,设置PWM信号占空比的范围
sp_servo.calibration(500, 2500, 1500)
cz_servo.calibration(500, 2500, 1500)# 初始化平移和倾斜的PID控制器
# 脱机运行或者禁用图像传输时使用这些PID值
sp_pid = PID(p=0.07, i=0, imax=90)
cz_pid = PID(p=0.05, i=0, imax=90)# 如果在线调试,使用这些PID值,之所以在线调试和脱机调试用不一样的PID参数,是因为在线调试数据有延迟
# pan_pid = PID(p=0.1, i=0, imax=90)
# tilt_pid = PID(p=0.1, i=0, imax=90)sensor.reset()  # 初始化摄像头传感器
sensor.set_pixformat(sensor.RGB565)  # 设置像素格式为RGB565
sensor.set_framesize(sensor.QQVGA)  # 设置分辨率为QQVGA以提高速度
sensor.skip_frames(1000)  # 让新设置生效
sensor.set_auto_whitebal(False)  # 关闭自动白平衡
sensor.set_auto_gain(False)  #关闭自动增益
clock = time.clock()  # 跟踪每秒帧数(FPS)#根据find_blobs()函数返回的blob列表的blob对象的第3、4个参数分别是像素的宽和高
def find_max(blobs):#每次调用该函数都会对参数作初始化max_size = 0max_blob = Nonefor blob in blobs:if blob[2] * blob[3] > max_size:max_blob = blobmax_size = blob[2] * blob[3]return max_blobwhile(True):clock.tick()  # 跟踪每次快照之间经过的毫秒数img = sensor.snapshot()  # 拍照并返回图像blobs = img.find_blobs([red_threshold])#如果识别到了色块if blobs:max_blob = find_max(blobs)#计算水平方向和垂直方向和图像中心的距离作为误差值sp_error = max_blob.cx() - img.width() / 2cz_error = max_blob.cy() - img.height() / 2print("sp_error:", sp_error)print("cz_error:", cz_error)img.draw_rectangle(max_blob.rect())  # 画出矩形img.draw_cross(max_blob.cx(), max_blob.cy())  # 画出十字sp_output = sp_pid.get_pid(sp_error, 1) / 2cz_output = cz_pid.get_pid(cz_error, 1)print("sp_output:", sp_output)print("cz_output:", cz_output)sp_servo.angle(sp_servo.angle() + sp_output)cz_servo.angle(cz_servo.angle() - cz_output)

9、pid.py代码

from pyb import millis  # 导入 pyboard 的 millis 函数,用于获取当前时间(毫秒)
from math import pi, isnan  # 导入 pi 和 isnan 函数class PID:# 定义 PID 控制器的参数和状态变量_kp = _ki = _kd = _integrator = _imax = 0_last_error = _last_derivative = _last_t = 0_RC = 1/(2 * pi * 20)  # RC 低通滤波器的时间常数def __init__(self, p=0, i=0, d=0, imax=0):# 初始化 PID 控制器的参数self._kp = float(p)  # 比例系数self._ki = float(i)  # 积分系数self._kd = float(d)  # 微分系数self._imax = abs(imax)  # 积分限制,防止积分饱和self._last_derivative = float('nan')  # 最后的导数值初始化为 NaNdef get_pid(self, error, scaler):tnow = millis()  # 获取当前时间dt = tnow - self._last_t  # 计算时间差output = 0  # 初始化输出值if self._last_t == 0 or dt > 1000:  # 如果是第一次运行或者时间差大于 1 秒dt = 0  # 重置时间差self.reset_I()  # 重置积分器self._last_t = tnow  # 更新最后时间戳delta_time = float(dt) / float(1000)  # 将时间差转换为秒output += error * self._kp  # 计算比例项if abs(self._kd) > 0 and dt > 0:  # 如果微分系数大于 0 且时间差大于 0if isnan(self._last_derivative):  # 如果最后的导数值为 NaNderivative = 0  # 设置导数为 0self._last_derivative = 0  # 重置最后的导数值else:derivative = (error - self._last_error) / delta_time  # 计算误差的导数# 使用低通滤波器平滑导数值derivative = self._last_derivative + ((delta_time / (self._RC + delta_time)) * (derivative - self._last_derivative))self._last_error = error  # 更新最后的误差值self._last_derivative = derivative  # 更新最后的导数值output += self._kd * derivative  # 计算微分项并加到输出中output *= scaler  # 按比例缩放输出值if abs(self._ki) > 0 and dt > 0:  # 如果积分系数大于 0 且时间差大于 0self._integrator += (error * self._ki) * scaler * delta_time  # 计算积分项并加到积分器中# 限制积分器的值在 -imax 和 imax 之间,防止积分饱和if self._integrator < -self._imax:self._integrator = -self._imaxelif self._integrator > self._imax:self._integrator = self._imaxoutput += self._integrator  # 将积分项加到输出中return output  # 返回计算的 PID 控制器输出值def reset_I(self):self._integrator = 0  # 重置积分器self._last_derivative = float('nan')  # 重置最后的导数值为 NaN

结语

如果大家发现有什么不对的地方,请斧正!

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

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

相关文章

asp.net core反向代理

新建项目 新建空白的asp.net core web项目 安装Yarp.ReverseProxy包版本为2.2.0-preview.1.24266.1 编写代码 namespace YarpStu01;public class Program {public static void Main(string[] args){var builder WebApplication.CreateBuilder(args);builder.Services.AddRev…

JavaWeb——MySQL:DQL

3. DQL:查询 查询是使用最多、最频繁的操作&#xff0c;因为前面的修改以及删除&#xff0c;一般会交给数据库专业的人员&#xff0c;对于非数据库专业人员来说&#xff0c;老板一般会放心的让你对数据库只进行查询操作&#xff1b; 3.2 条件查询&#xff08;where&#xff09…

浏览器自带的IndexDB的简单使用示例--小型学生管理系统

浏览器自带的IndexDB的简单使用示例--小型学生管理系统 文章说明代码效果展示 文章说明 本文主要为了简单学习IndexDB数据库的使用&#xff0c;写了一个简单的增删改查功能 代码 App.vue&#xff08;界面的源码&#xff09; <template><div style"padding: 30px&…

2024年通信技术与计算机科学国际学术会议(ICCTCS 2024)

2024年通信技术与计算机科学国际学术会议&#xff08;ICCTCS 2024&#xff09; 2024 International Academic Conference on Communication Technology and Computer Science&#xff08;ICCTCS 2024&#xff09; 会议简介&#xff1a; 2024年通信技术与计算机科学国际学术会议…

Leetcode.1735 生成乘积数组的方案数

题目链接 Leetcode.1735 生成乘积数组的方案数 rating : 2500 题目描述 给你一个二维整数数组 q u e r i e s queries queries &#xff0c;其中 q u e r i e s [ i ] [ n i , k i ] queries[i] [n_i, k_i] queries[i][ni​,ki​] 。第 i i i 个查询 q u e r i e s [ i …

JAVA SDK 整合 AI 大语言模型

目前主流模型厂商的 SDK 并没有很好的支持 JAVA 环境&#xff0c;主流还是使用的 Python &#xff0c;如果希望将 AI 功能集成到业务中来&#xff0c;则需要找找有没有一些现成的开源项目&#xff0c;但是这种项目一般需要谨慎使用&#xff0c;以防有偷取 app_key 等风险问题 前…

如何在Linux下使用git(几步把你教会)

目录 一、注册github账号 二、新建项目 1.点击右上角自己的头像&#xff0c;然后点击Your repositories。 2.点击New。 3.配置新项目信息。 4.点击Create repository即可成功创建。 三、安装git 四、配置git 五、初始化git仓库 1.先进入想要使用git的目录。 2.初始化…

数据时代的数字企业

1.写在前面 讨论数据治理在数字企业中的影响和必要性&#xff0c;并介绍数据治理的核心内容和实践方法。作者强调了数据质量、数据安全、数据隐私和数据合规等方面是数据治理的核心内容&#xff0c;并介绍了具体的实践措施和案例分析。企业需要重视这些方面以实现数字化转型和…

多孔散热器简介

今天给大家分享关于多孔散热器的一些构造、散热情况。 更多资讯&#xff0c;请关注B站【莱歌数字】&#xff0c;有视频教程~~ 常见的散热器通常由不渗透水、空气和其他液体的无孔材料制成。固体铝和铜是行业标准。 但散热器也可以作为半多孔材料或多孔涂层。研究和应用表明&…

防静电监控系统全方位防静电监测,保障产品质量

在当今高度精密的电子制造领域&#xff0c;产品质量的保障至关重要。哪怕是微小的静电干扰&#xff0c;都可能导致电子元件损坏、性能下降&#xff0c;从而影响整个产品的质量和可靠性。为了应对这一挑战&#xff0c;某电子工厂车间引入了先进的防静电监控系统&#xff0c;实现…

11g rac db安装软件时找不到 节点的问题处理

问题 在安装11.2.0.4db软件时数据库软件无法识别集群的两个主机 处理方法 [oracleracdg1-1 database]$ cd /u01/app/oraInventory/ [oracleracdg1-1 oraInventory]$ ls ContentsXML logs oraInst.loc orainstRoot.sh oui [oracleracdg1-1 oraInventory]$ cd ContentsXML/…

Qt | QSS自定义部件的外观

01、简介 一、自定义部件外观基础 1、有 3 种方法可实现自定义界面外观:重新实现 paintEvent()函数,使用 QStyle 类的绘制函数,子类化 QStyle,本小节仅介绍方法 1 和 2 的使用方式,方法 3 见下一节。 2、方法一:Qt 通过 QWidget::paintEvent()函数实现界面外观的绘制,…

Linux运行jar包:Invalid or corrupt jarfile

你们好&#xff0c;我是金金金。 场景 maven打包springboot项目得到一个jar包&#xff0c;我通过xshell上传到虚拟机环境里面&#xff0c;试图运行它&#xff0c;结果Invalid or corrupt jarfile&#xff1a;jar 文件无效或损坏 排查 jdk版本是否一致&#xff1f;结果&#xf…

参数页面设计

目录 一 设计原型 二 后台源码 一 设计原型 二 后台源码 namespace 参数页面设计 {public partial class Form1 : Form{List<PMs> PMs new List<PMs>();public Form1(){InitializeComponent();}private void Form1_Load(object sender, EventArgs e){for (int …

深入解析 Python dataclass:类属性与类方法解释

文章目录 dataclass实例属性和类属性自动设置属性 实例方法静态方法&#xff08;staticmethod&#xff09;和 类方法&#xff08;classmethod&#xff09;静态方法类方法 dataclass dataclass 是 Python 3.7 引入的一个装饰器&#xff0c;用于简化类的定义。 使用 dataclass …

Django教程(001):安装及快速上手

1.1 Django安装 pip install django安装之后 c:\python39-python.exe-Scripts-pip.exe-django-admin.exe【安装django之后&#xff0c;工具&#xff0c;创建django项目】-Lib-内置模块-site-packages-flask-django(安装django之后&#xff0c;【django框架源码】)如下图&…

思考题:相交的几何图形

给定不超过 26 个几何图形&#xff0c;每个图形都有一个唯一大写字母作为其编号。 每个图形在平面中的具体位置已知&#xff0c;请你判断&#xff0c;对于每个图形&#xff0c;有多少个其他图形与其存在交点。 在判断交点时&#xff0c;只考虑边与边相交的情况&#xff0c;如…

AIGC+艺术=教育变革?

在数字化时代的浪潮中&#xff0c;技术的每一次跃进都深刻影响着社会的各个领域&#xff0c;教育亦不例外。近年来&#xff0c;人工智能生成内容&#xff08;AIGC&#xff09;技术的兴起&#xff0c;为艺术教育领域带来了前所未有的变革机遇。当AIGC与艺术相结合&#xff0c;我…

vscode 删除不用的ssh远程连接

使用vscode连接一个远程服务器发现联不通&#xff0c;但是使用mobaxterm是可以通的&#xff0c;最后原因发现是这个服务器ip与之前连过的另一台相同&#xff0c;和之前连接保存的信息冲突了 解决办法&#xff1a; 使用记事本打开这个路径下的known_hosts(最好备份一下)&#x…

电脑打印文件怎么操作?

有打印机用户的打印操作 对于已经拥有打印机的用户来说&#xff0c;打印文件通常是一个简单的步骤。首先&#xff0c;你需要将你的文件&#xff08;如Word、PDF、PPT等&#xff09;在电脑上打开。然后&#xff0c;点击菜单栏中的“打印”选项&#xff0c;或者快捷键CtrlP&…