基于Openmv的追小球的云台

news2024/10/7 14:25:33

介绍

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

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

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 = 0
    max_blob = None
    for blob in blobs:
        if blob[2] * blob[3] > max_size:
            max_blob = blob
            max_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) / 2
 cz_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 = 0
    max_blob = None
    for blob in blobs:
        if blob[2] * blob[3] > max_size:
            max_blob = blob
            max_size = blob[2] * blob[3]
    return max_blob

while(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() / 2
        cz_error = max_blob.cy() - img.height() / 2

        print("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) / 2
        cz_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')  # 最后的导数值初始化为 NaN

    def 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 且时间差大于 0
            if isnan(self._last_derivative):  # 如果最后的导数值为 NaN
                derivative = 0  # 设置导数为 0
                self._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 且时间差大于 0
            self._integrator += (error * self._ki) * scaler * delta_time  # 计算积分项并加到积分器中
            # 限制积分器的值在 -imax 和 imax 之间,防止积分饱和
            if self._integrator < -self._imax:
                self._integrator = -self._imax
            elif self._integrator > self._imax:
                self._integrator = self._imax
            output += self._integrator  # 将积分项加到输出中

        return output  # 返回计算的 PID 控制器输出值

    def reset_I(self):
        self._integrator = 0  # 重置积分器
        self._last_derivative = float('nan')  # 重置最后的导数值为 NaN

结语

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

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

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

相关文章

基于 RGB的热成像无人机树冠数据集(目标检测)

亲爱的读者们&#xff0c;您是否在寻找某个特定的数据集&#xff0c;用于研究或项目实践&#xff1f;欢迎您在评论区留言&#xff0c;或者通过公众号私信告诉我&#xff0c;您想要的数据集的类型主题。小编会竭尽全力为您寻找&#xff0c;并在找到后第一时间与您分享。 摘要&a…

Hightec编译器系列之高级调试技巧精华总结

Hightec编译器系列之高级调试技巧精华总结 小T为了便于大家理解&#xff0c;本文的思维导图大纲如下&#xff1a; 之前可能很多小伙伴没有使用过Hightec编译器&#xff0c;大家可以参考小T之前的文章《Hightec编译器系列之白嫖就是爽》可以下载一年试用版本。 小T使用过适配英…

vue中图谱关系插件relation-graph

vue中图谱关系插件relation-graph 一、效果图二、安装下载&#xff08;vue2.0版本的&#xff09;三、直接上代码 一、效果图 二、安装下载&#xff08;vue2.0版本的&#xff09; npm install --save relation-graph var foo bar;三、直接上代码 <template><div cla…

Notepad++插件 Hex-Edit

Nptepad有个Hex文件查看器&#xff0c;苦于每次打开文件需要手动开插件显示Hex&#xff0c;配置一下插件便可实现打开即调用 关联多个二进制文件&#xff0c;一打开就使用插件的方法&#xff0c;原来是使用空格分割&#xff01;&#xff01;&#xff01;

MySQL中的Redo-log是什么?有什么作用?

用来实现数据的恢复&#xff0c;数据被更新到缓冲区但没刷磁盘&#xff0c;然后MySQL宕机了&#xff0c;MySQL会通过日志恢复数据。 1.为什么需要Redo-log日志&#xff1f; MySQL绝大部分引擎都是基于磁盘存储数据的&#xff0c;每次读写数据都走磁盘&#xff0c;效率十分低下…

jar包转exe封装软件并一键安装使用

目录 封装文档说明如有跨域问题在ems服务增加配置服务启动自动打开浏览器使用工具 Launch4j 把jar包打成exe执行文件现在还不能给用户用&#xff0c;因为缺少jre&#xff0c;后面整合资源会把jre一起打包使用inno setup合并资源&#xff0c;mysql之类的服务&#xff0c;最终打包…

鸿蒙 HarmonyOS NEXT星河版APP应用开发-阶段二

一、鸿蒙应用界面开发 弹性布局-Flex 语法 /* 弹性容器组件 Flex() 位置&#xff1a; Flex默认主轴水平往右&#xff0c;交叉轴垂直向下&#xff08;类似Row&#xff09; 语法&#xff1a; Flex(参数对象){子组件1,子组件2,子组件3 } 属性方法&#xff1a; direction&#xf…

2-15 基于matlab的蚁群,模拟退火,遗传,神经网络,禁忌搜索等智能优化算法对TSP问题

基于matlab的蚁群&#xff0c;模拟退火&#xff0c;遗传&#xff0c;神经网络&#xff0c;禁忌搜索等智能优化算法对TSP问题。五种优化算法对多个城市路径进行规划&#xff0c;通过优化速度、距离可比较五种方法的优劣。程序已调通&#xff0c;可直接运行。 2-15 蚁群优化算法 …

【UEFI实战】HttpBoot

环境配置 首先下载tftpd工具&#xff0c;可以在phjounin / tftpd64 / Downloads — Bitbucket下载到&#xff0c;建议不要安装到C盘&#xff0c;因为可能无法修改其配置。配置tftpd工具的DHCP服务&#xff1a; 注意这里的IP地址需要跟实际网卡IP匹配。 下载Apache&#xff0c…

短视频矩阵系统搭建部署,AI剪辑短视频,矩阵发布,一键管理矩阵账号

目录 前言&#xff1a; 一、短视频矩阵系统功能是怎么样的&#xff1f; 二、怎么制作这样一款系统&#xff1f; 总结&#xff1a; 前言&#xff1a; AI短视频矩阵系统&#xff0c;利用AI编辑短视频的功能&#xff0c;将素材上传到系统里面&#xff0c;AI可以自动剪辑成新的短…

【计算机视觉】人脸算法之图像处理基础知识【七】

直方图均衡化 直方图均衡化是一种常用的图像处理技术&#xff0c;用于改善图像的对比度&#xff0c;特别是在图像的细节被埋没在暗部或亮部区域时。通过重新分配图像的像素强度值&#xff0c;使得图像的整体对比度增强&#xff0c;从而让更多的细节变得可见。 import cv2 imp…

关于NACHI机器人语言程序的反编译

所谓反编译&#xff0c;是指将执行形式的程序转换为机器人语言程序&#xff08;ASCII 文件&#xff09;。作业程序&#xff08;执行形式&#xff09;→机器人语言程序&#xff08;源程序&#xff09;。 机器人语言的源程序为纯文本形式&#xff0c;可使用个人电脑的文本编辑器…

针对AIGC检测的鲁棒性测试——常见攻击手段汇总

前言&#xff1a;这篇文章来总结一下针对AIGC检测的常见攻击手段&#xff0c;选取的研究工作均出自近5年AIGC检测相关文章。&#xff08;论文被拒了需要补实验&#xff0c;先来看看别人怎么做的……&#xff09; 2019 WIFS Detecting and Simulating Artifacts in GAN Fake Ima…

Charles抓包工具系列文章(一)-- Compose 拼接http请求

一、背景 众所周知&#xff0c;Charles是一款抓包工具&#xff0c;当然是http协议&#xff0c;不支持tcp。&#xff08;如果你想要抓tcp包&#xff0c;请转而使用wireshark&#xff0c;在讲述websocket的相关技术有梳理过wireshark抓包&#xff09; 话说回来&#xff0c;char…

企业文件传输系统只能传输?分享功能同样重要!(上)

在当今的商业世界里&#xff0c;企业间的协作和信息交流已经变得极其重要&#xff0c;特别是在处理那些庞大的文件时。想象一下&#xff0c;设计图、高清视频、大数据分析&#xff0c;还有软件开发包&#xff0c;这些文件的大小往往达到GB甚至TB级别&#xff0c;它们是企业日常…

守护生产车间安全:可燃气体报警器预警与检测的重要性

近日&#xff0c;东莞一材料厂发生的火灾事故再次敲响了工业安全生产的警钟。 这起事故不仅给工厂带来了巨大的经济损失&#xff0c;也暴露了一些企业在安全管理方面的疏漏。其中&#xff0c;可燃气体报警器的应用与预警功能在火灾防范中扮演了至关重要的角色。 接下来&#…

AlgorithmStar 度量 计算组件

AlgorithmStar 度量 计算组件 AlgorithmStar 本文将会基于 AlgorithmStar 1.40 以及以上的版本来演示&#xff0c;度量 计算 组件 的使用&#xff01; 目录 文章目录 AlgorithmStar 度量 计算组件目录获取到依赖库度量计算组件 计算实例距离计算代表 - 欧几里德距离计算组件…

麒麟信安系统关闭core文件操作

在使用麒麟信安系统时&#xff0c;如果应用程序运行过程中崩溃了&#xff0c;此时并不会导致内核崩溃&#xff0c;只会在tmp目录下产生崩溃数据&#xff0c;如下图 不过tmp目录下的分区容量有限&#xff0c;当崩溃的应用core文件过大时将会占用tmp空间&#xff0c;导致tmpfs分区…

零代码搭建AI应用-文心智能体的设计与实现

本教程旨在帮助你开发一个结合语音识别和信息查询技术的智能应用&#xff0c;为用户提供登山小技巧和心得体会&#xff0c;满足用户在户外运动中的需求。通过设计不同角色和场景&#xff0c;可以满足用户在不同生活领域的需求&#xff0c;例如在家庭、社交、职场等场景下提供不…

37. 变焦镜头

导论&#xff1a; 设计好的一组镜头如果变化镜片与镜片之间的空气厚度&#xff0c;镜头的焦距会随之变化。 通常来说一个系统的接收面尺寸大小是固定不变的。 设计要求&#xff1a; 设计一个简单的变焦镜头&#xff1a;入瞳直径25mm&#xff0c;焦距75~125mm&#xff0c;像…