舵机云台实现追踪球形目标功能

news2024/7/6 20:43:08

1. 功能说明

      在样机舵机云台上安装一个摄像头,本文示例将实现舵机云台追踪球形物体的功能。

 2. 电子硬件

      在这个示例中,我们采用了以下硬件,请大家参考:

主控板

Basra主控板(兼容Arduino Uno)‍

扩展板

Bigfish2.1扩展板‍

电池7.4V锂电池

通信

2510通信转接板

WiFi路由器

其它

摄像头

配置OpenCV的Visual Studio 2015.net环境‍ 的计算机一台

电路连接说明:

      ① 将2510通信转接板连接到Bigfish扩展板的扩展坞上面;

      ② 用3根母对母杜邦线将2510通信转接板与WiFi路由器连接起来:GND-GND、RX-RX、TX-TX;

      ③ 找到1根USB线,一端连接到2510通信转接板接口上,另一端连接到WiFi路由器USB接口上;

      ④ 将摄像头线连接到WiFi路由器接口上。

3. 功能实现

   实现思路:实现舵机云台追踪蓝色小球。

3.1 工作原理

   ① 摄像头采集图像信息;

   ② 通过WiFi将图像信息传递给PC端(VS2015配置的OpenCV环境);

   ③ 在PC端使用OpenCV对图像转化为灰度图像;

   ④ 检测圆形,并且计算出圆中心坐标;

   ⑤ 采用九宫格方式对摄像显示图像进行分割;

   ⑥ 确定目标物体在显示图像的所处九宫格位置;

   ⑦ 如果目标图像超出九宫格位置的中心,调整摄像头矫正偏移使目标物体在屏幕中心位置;

   ⑧ 调整摄像头需要上位机通过WiFi给下位机发送矫正指令,下位机需要接收信号,并且让安装了摄像头的舵机云台做出相应的矫正动作。

3.2 示例程序

     编程环境:Arduino 1.8.19

① 下位机例程

      将参考例程(example.ino)下载到主控板,开启路由器,将路由器与主控板TX、Rx串口进行连接,同时将PC连接至路由器WIFI网络。下位机接收上位机处理的图像信息结果控制舵机云台相应运动,云台跟随目标物体运动。

/*------------------------------------------------------------------------------------

   版权说明:Copyright 2023 Robottime(Beijing) Technology Co., Ltd. All Rights Reserved.

           Distributed under MIT license.See file LICENSE for detail or copy at

           https://opensource.org/licenses/MIT

           by 机器谱 2023-04-24 https://www.robotway.com/

   ------------------------------*/

#include <Servo.h>

#define BOTTOM_SERVO_MIN 10

#define BOTTOM_SERVO_MAX 175

#define TOP_SERVO_MIN 85

#define TOP_SERVO_MAX 175

const String CMD_UP = "U";

const String CMD_DOWN = "D";

const String CMD_LEFT = "L";

const String CMD_RIGHT = "R";

Servo myServo[2];

int servo_value[2] = {85, 105};

int port0 = 4;

int port1 = 7;

int servo_move_angle = 1;

void setup()

{

   Serial.begin(9600);

   ServoInit();

   delay(1000);

}

void loop()

{

   String s = SerialRead();

   

   if(s != "")

   {

    if(s == CMD_UP)

      ServoAdjust(port1, -servo_move_angle);

    else if(s == CMD_DOWN)

      ServoAdjust(port1, servo_move_angle);

    else if(s == CMD_LEFT)

      ServoAdjust(port0, -servo_move_angle);

    else if(s == CMD_RIGHT)

      ServoAdjust(port0, servo_move_angle);

   }

}

String SerialRead()

{

   String str = "";

   while(Serial.available())

   {

    str += char(Serial.read());

   }

   return str;

}

void ServoInit()

{

   myServo[0].attach(port0);

   myServo[1].attach(port1);

   

   for(int i=0;i<2;i++)

   {

    myServo[i].write(servo_value[i]);

   }

}

void ServoAdjust(int which, int where)

{

   switch(which)

   {

    case 4:

      servo_value[0] += where;

     

      if(servo_value[0] <= BOTTOM_SERVO_MIN)

        servo_value[0] = BOTTOM_SERVO_MIN;

      else if(servo_value[0] >= BOTTOM_SERVO_MAX)

        servo_value[0] = BOTTOM_SERVO_MAX;

     

      myServo[0].write(servo_value[0]);

      break;

    case 7:

      servo_value[1] += where;

     

      if(servo_value[1] <= TOP_SERVO_MIN)

        servo_value[1] = TOP_SERVO_MIN;

      else if(servo_value[1] >= TOP_SERVO_MAX)

        servo_value[1] = TOP_SERVO_MAX;

     

      myServo[1].write(servo_value[1]);

      break;

    default:

      break;

   }

}

② 上位机例程

     下面提供一个可以实现舵机云台追踪球形物体的参考例程(MainWindow.xaml.cs),大家可参考演示视频完成该实验。

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Navigation;

using System.Windows.Shapes;

using System.Windows.Forms;

using System.Runtime.InteropServices;

using System.Threading;

using System.Net;

using System.Net.Sockets;


namespace Project

{

    /// <summary>

    /// 形状跟踪,球

    /// </summary>

    public partial class MainWindow : Window

    {

        //导入 HoughCircles.dll 动态链接库

        [DllImport("HoughCircles_DLL")]

        public static extern void HoughCircles([MarshalAs(UnmanagedType.LPStr)]string ip_address, //视频地址

                                                                                    ref int xpos, //跟踪物体中心X坐标

                                                                                    ref int ypos); //跟踪物体中心Y坐标


        //定义窗口大小

        int cap_w = 320, cap_h = 240;

        //跟踪物体中心 x, y 坐标值,物体轮廓半径r

        int x = 0, y = 0;

        //定义命令变量

        string CMD_UP = "", CMD_DOWN = "", CMD_TURN_LEFT = "", CMD_TURN_RIGHT = "";

        //结构体

        public struct Boundaries

        {

            public int x_left;

            public int x_right;

            public int y_up;

            public int y_down;

        }

        Boundaries boundaries = new Boundaries();


        public MainWindow()

        {

            InitializeComponent();

        }


        private void Window_Loaded(object sender, RoutedEventArgs e)

        {

            GetIni();

            SetPosition();

            CmdInit();

            StructInit();

        }


        //变量初始化

        private void CmdInit()

        {

            CMD_UP = "U";

            CMD_DOWN = "D";

            CMD_TURN_LEFT = "L";

            CMD_TURN_RIGHT = "R";

        }


        //结构体初始化

        private void StructInit()

        {

            boundaries.x_left = 100;

            boundaries.x_right = 200;

            boundaries.y_up = 80;

            boundaries.y_down = 160;

        }


        //获取ini配置文件信息

        private void GetIni()

        {

            ini_RW.FileName = System.Windows.Forms.Application.StartupPath + "\\Config.ini";

            this.videoAddress.Text = ini_RW.ReadIni("VideoUrl", "videourl", "");

            this.ipAddress.Text = ini_RW.ReadIni("ControlUrl", "controlUrl", "");

            this.portBox.Text = ini_RW.ReadIni("ControlPort", "controlPort", "");

        }


        //修改配置

        private void setBtn_Click(object sender, RoutedEventArgs e)

        {

            ini_RW.WriteIni("VideoUrl", "videourl", this.videoAddress.Text);

            ini_RW.WriteIni("ControlUrl", "controlUrl", this.ipAddress.Text);

            ini_RW.WriteIni("ControlPort", "controlPort", this.portBox.Text);


            System.Windows.MessageBox.Show("配置成功!请重启程序以使配置生效。", "配置信息", MessageBoxButton.OK, MessageBoxImage.Information);

            //this.Close();

        }


        //命令发送函数

        void SendData(string data)

        {

            try

            {

                IPAddress ips = IPAddress.Parse(ipAddress.Text.ToString());//("192.168.8.1");

                IPEndPoint ipe = new IPEndPoint(ips, Convert.ToInt32(portBox.Text.ToString()));//把ip和端口转化为IPEndPoint实例

                Socket c = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//创建一个Socket


                c.Connect(ipe);//连接到服务器


                byte[] bs = Encoding.ASCII.GetBytes(data);

                c.Send(bs, bs.Length, 0);//发送测试信息

                c.Close();

            }

            catch (Exception e)

            {

                System.Windows.Forms.MessageBox.Show(e.Message);

            }

        }


        //跟踪物体位置界限判断

        private void LineDetect(int _x, int _y)

        {

            if (_x > 0 && _x <= boundaries.x_left)

            {

                SendData(CMD_TURN_LEFT);

            }

            else if (x > boundaries.x_right && x < cap_w)

            {

                SendData(CMD_TURN_RIGHT);

            }

            else if (_y > 0 && _y <= boundaries.y_up)

            {

                SendData(CMD_DOWN);

            }

            else if (_y > boundaries.y_down && _y < cap_h)

            {

                SendData(CMD_UP);

            }

        }


        //物体位置初始化#FFACAAAA

        private void SetPosition()

        {

            var color = new SolidColorBrush((System.Windows.Media.Color)System.Windows.Media.ColorConverter.ConvertFromString("#00008B"));

            objEllipse.Height = 30;

            objEllipse.Width = 30;

            objEllipse.Fill = color;


            var left_distance = (cap_w - objEllipse.Width) / 2;

            var top_distance = (cap_h - objEllipse.Height) / 2;


            Canvas.SetLeft(objEllipse, left_distance);

            Canvas.SetTop(objEllipse, top_distance);

        }


        //跟踪物体位置更新函数

        private void PositionUpdate(int x, int y)

        {

            LineDetect(x, y);


            Canvas.SetLeft(objEllipse, x);

            Canvas.SetTop(objEllipse, y);


            posLable.Content = x + " , " + y;

        }


        //线程函数

        private void ThreadCapShow()

        {

            try

            {

                while (true)

                {

                    this.Dispatcher.Invoke(

                        new Action(

                            delegate

                            {

                                string ip = this.videoAddress.Text;

                                HoughCircles(ip, ref x, ref y);

                                PositionUpdate(x - 15, y - 15);

                            }

                            ));

                }


            }

            catch { };

        }


        //打开跟踪窗口

        private void openBtn_Click(object sender, RoutedEventArgs e)

        {

            try

            {

                Thread m_thread = new Thread(ThreadCapShow);

                m_thread.IsBackground = true;

                m_thread.Start();

            }

            catch { };

        }

    }

}

例程源代码、样机3D文件资料内容详见 舵机云台-追踪球形目标

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

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

相关文章

Linux之创建进程、查看进程、进程的状态以及进程的优先级

文章目录 前言一、初识fork1.演示2.介绍3.将子进程与父进程执行的任务分离4.多进程并行 二、进程的状态1.进程的状态都有哪些&#xff1f;2.查看进程的状态2.运行&#xff08;R&#xff09;3.阻塞4.僵尸进程&#xff08;Z&#xff09;1.僵尸状态概念2.为什么要有僵尸状态&#…

Rust每日一练(Leetday0011) 下一排列、有效括号、搜索旋转数组

目录 31. 下一个排列 Next Permutation &#x1f31f;&#x1f31f; 32. 最长有效括号 Longest Valid Parentheses &#x1f31f;&#x1f31f;&#x1f31f; 33. 搜索旋转排序数组 Search-in-rotated-sorted-array &#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷…

开发 Microsoft 365 Copilot Plugin!

大家好&#xff01;我是韩老师。 昨天凌晨的微软 Build 大会&#xff0c;大家都看了吗&#xff1f; 我看到了凌晨两点&#xff0c;且毫无困意&#xff01; 真的是干货满满~ 列举几个比较大的发布&#xff1a;1. Windows Copilot2. Bing 成为 ChatGPT 的默认搜索体验3. AI 插件生…

一起看 I/O | 移动设备、Web、AI 和 Google Cloud 更新一览

作者 / Developer X 副总裁兼总经理、开发者关系主管 Jeanine Banks 感谢您再次与我们共享 Google I/O 大会的精彩&#xff01;我们正在持续深度投入资源来提升 AI、移动设备、Web 和 Google Cloud&#xff0c;致力于让您的开发工作更加轻松。现在&#xff0c;您看到了许多我们…

实测「360智脑」的真正实力:能否领跑国内百“模”大战?

ChatGPT 的发布&#xff0c;无疑掀起了一股“AI 技术”新浪潮。百度文心一言、华为盘古、商汤日日新、阿里通义千问、讯飞星火等众多大模型的接连问世&#xff0c;使得国内的“百模之战”进入了前所未有的白热化阶段。无论是各大互联网巨头&#xff0c;还是清华、复旦等知名高校…

聊聊「短信」渠道的设计与实现

有多久&#xff0c;没有发过短信了&#xff1f; 一、背景简介 在常规的分布式架构下&#xff0c;「消息中心」的服务里通常会集成「短信」的渠道&#xff0c;作为信息触达的重要手段&#xff0c;其他常用的手段还包括&#xff1a;「某微」、「某钉」、「邮件」等方式&#xff…

多种群遗传算法的函数优化算法

以下内容大部分来源于《MATLAB智能算法30个案例分析》&#xff0c;仅为学习交流所用。 1 理论基础 1.1 遗传算法早熟问题 遗传算法是一种借鉴生物界自然选择和进化机制发展起来的高度并行、随机、自适应的全局优化概率搜索算法。由于优化时不依赖于梯度&#xff0c;具有很强…

拥抱新时代的Java

原文链接 拥抱新时代的Java Java作为面向对象编程的王牌语言&#xff0c;曾经风靡一时&#xff0c;在Web领域是绝对的老大。随着时间的推移&#xff0c;一些新的编程范式不断的涌现&#xff0c;如函数式编程&#xff0c;响应式编程&#xff0c;以及对函数的全力支持&#xff0…

北邮22信通:实验五 共射放大电路的频率特性与深负反馈的影响

北邮22信通一枚~ 很高兴以一个新身份与大家见面~ 关注作者&#xff0c;解锁更多邮苑模电实验报告~ 获取更多文章&#xff0c;请访问专栏&#xff1a; 北邮22信通——电子电路_青山如墨雨如画的博客-CSDN博客 目录 实验目的&#xff1a; 实验设备及器件&#xff1a; …

区间预测 | MATLAB实现QGPR高斯过程分位数回归多变量时间序列区间预测

区间预测 | MATLAB实现QGPR高斯过程分位数回归多变量时间序列区间预测 目录 区间预测 | MATLAB实现QGPR高斯过程分位数回归多变量时间序列区间预测效果一览基本介绍模型描述程序设计参考资料 效果一览 基本介绍 MATLAB实现QGPR高斯过程分位数回归多变量时间序列区间预测 1.基于…

可用于Stable Diffusion免费的AI绘画标签生成器

这是一个开源项目&#xff0c;借花献佛&#xff0c;基于原作者的基础上进行了微调还有以及修改内容。 支持中英文&#xff0c;权重以及xxxx词汇&#xff0c;老司机都懂。 直接可在右侧根据需求进行点选操作&#xff0c;然后复制到自己的Stable Diffusion中进行AI绘画。 下载…

【产品经理】移动手机区别于PC端的10点特性

众所周知&#xff0c;当今时代已经是移动互联网时代。相比以前大家热衷于在电脑上浏览网页、玩游戏的情形&#xff0c;现在大家都喜欢通过移动手机去满足个人方方面面的需求&#xff0c;无论是购物、吃饭、求职、阅读、聊天、游戏等等。也就是说&#xff0c;在日常的生活中&…

ChatGPT变现赚钱 第二篇

前面我们已经介绍了一些利用ChatGPT做变现的一些玩法&#xff0c;比如做微信问一问的回答&#xff0c;做AI剪映的一键生成视频的(星球里面有详细的指南和视频)。 现在我们会员群在玩百度问一问答题&#xff0c;这个项目蛮好的&#xff0c;成本很低&#xff0c;现在又有苹果手机…

利用视听短片从自然刺激中获得开放的多模式iEEG-fMRI数据集

在认知神经科学领域&#xff0c;数据共享和开放科学变得越来越重要。虽然许多参与认知神经科学实验的志愿者的数据集现在是公开可用的&#xff0c;但颅内脑电图&#xff08;iEEG&#xff09;数据的共享相对较少。iEEG是一种高时间和空间分辨率的记录技术&#xff0c;通过在患者…

组长给组员派活,把组长自己的需求和要改的bug派给组员,合理吗?

组长把自己的工作派给手下&#xff0c;合理吗&#xff1f; 一位程序员问&#xff1a; 组长给他派活&#xff0c;把组长自己的需求或者要改的bug派给他。组长分派完需求之后&#xff0c;他一个人干两个项目&#xff0c;组长却无所事事&#xff0c;这样合理吗&#xff1f; 有人说…

微服务开发系列 第七篇:RocketMQ

总概 A、技术栈 开发语言&#xff1a;Java 1.8数据库&#xff1a;MySQL、Redis、MongoDB、Elasticsearch微服务框架&#xff1a;Spring Cloud Alibaba微服务网关&#xff1a;Spring Cloud Gateway服务注册和配置中心&#xff1a;Nacos分布式事务&#xff1a;Seata链路追踪框架…

华为OD机试真题 Java 实现【打印文件】【2023Q1 100分】

一、题目描述 有 5 台打印机打印文件&#xff0c;每台打印机有自己的待打印队列。 因为打印的文件内容有轻重缓急之分&#xff0c;所以队列中的文件有1~10不同的优先级&#xff0c;其中数字越大优先级越高。 打印机会从自己的待打印队列中选择优先级最高的文件来打印。 如果…

Linux常用命令——help命令

在线Linux命令查询工具 help 显示帮助信息 补充说明 help命令用于显示shell内部命令的帮助信息。help命令只能显示shell内部的命令帮助信息。而对于外部命令的帮助信息只能使用man或者info命令查看。 语法 help(选项)(参数)选项 -s&#xff1a;输出短格式的帮助信息。仅…

冯斌:突破认知临界点,打造自驱型团队 | 开发者说

熟悉冯斌的人&#xff0c;大都直接称呼其网名 Kid&#xff0c;包括他在 ONES 的同事。人如其名&#xff0c;Kid 的寓意就是「用孩子的眼光看世界」&#xff0c;返璞归真的思维方式才能发现新大陆。正如毕加索说的&#xff1a;「我一生都在向孩子学习。」 在 ONES 联合创始人兼 …

设计师解放双手之作!3秒生成风景园林效果图,AIGC赋能景观设计

‍ 项目简介 在过去几十年&#xff0c;风景园林经历了从“刀耕火种”的完全手绘设计时代到当下比较流行的参数化设计时代&#xff0c;过去的每一轮技术革新都让风景园林作品的表现形式产生了巨大的改变。随着计算机图像技术的发展&#xff0c;我们有更多的建模和渲染软件辅助提…