双轮云台小车实现追踪彩色目标功能

news2025/1/9 5:05:50

1. 功能说明

     在R216a样机上安装一个摄像头,本文示例将实现双轮小车通过二自由度云台自主寻找彩色目标的功能。

 2. 结构说明

      R216a样机主要是由一个 双轮小车 和一个 2自由度云台 组合而成。

3. 电子硬件

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

主控板

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路由器接口上。

4. 功能实现

    实现思路:实现双轮云台小车追踪蓝色小球。

4.1 工作原理

    ① 摄像头采集图像信息;

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

    ③ 使用OpenCV的目标颜色跟踪camshift算法取得目标物体的中心点坐标;

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

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

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

    ⑦ 调整摄像头需要上位机通过WiFi给下位机发送矫正指令,下位机需要接收信号,并且让安装了摄像头的智能小车做出相应的矫正动作,

         如果丢失目标,智能车上的云台会转动以寻找目标。

4.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/

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

/*

  car_exapmle

  2018/06/07

  ---------------------

  Motor:

    left: 9,5

    right: 10,6

  Servo:

    bottom:4

    top:7

*/

#include <Servo.h>


#define BOTTOM_SERVO_MIN 60

#define BOTTOM_SERVO_MAX 150   //175

#define BOTTOM_SERVO_MIDDLE 85

#define TOP_SERVO_MIN 85

#define TOP_SERVO_MAX 175


const String CMD_LEFT = "L";

const String CMD_RIGHT = "R";

const String CMD_STOP = "S";

const String CMD_FORWARD = "F";

const String CMD_LOST = "N";


Servo myServo[2];

int port0 = 4;

int port1 = 7;

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

int servo_move_angle = 1;


void setup() {

  Serial.begin(9600);

  pinMode(5,OUTPUT);

  pinMode(6,OUTPUT);

  pinMode(9,OUTPUT);

  pinMode(10,OUTPUT);

  ServoInit();

  delay(1000);

}


void loop() {

  String data = SerialRead();

  if(data == CMD_STOP)

  {

    Stop();

  }

  else if(data == CMD_FORWARD)

  {

    Forward();

  }

  else if(data == CMD_LEFT)

  {

    Left();

    delay(60);

    Stop();

  }

  else if(data == CMD_RIGHT)

  {

    Right();

    delay(60);

    Stop();

  }

  else if(data == CMD_LOST)

  {

    FindObject();

  }

}


String SerialRead()

{

  String str = "";

  while(Serial.available())

  {

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

  }

  return str;

}


int Angle2Pwm(int n)

{

  return map(n, 0, 180, 500, 2500);

}


void ServoInit()

{

  myServo[0].attach(port0);

  myServo[1].attach(port1);

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

  {

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

  }

}


void FindObject()

{

  const int times = 30;

  int dir = 0;

  for(;;)

  {

    String data = SerialRead();  

    if(data != CMD_LOST && data != "")

    {

      if(servo_value[0] <= BOTTOM_SERVO_MIDDLE)

      {

        dir = 1;   // turn   left

        for(int i=0;i<abs(servo_value[0] - BOTTOM_SERVO_MIDDLE);i++)

        {

          servo_value[0] += 1;

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

          delay(times);

        }

      }

      else if(servo_value[0] > BOTTOM_SERVO_MIDDLE)

      {

        dir = 2;   // turn right

        for(int i=0;i<abs(servo_value[0] - BOTTOM_SERVO_MIDDLE);i++)

        {

          servo_value[0] -= 1;

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

          delay(times);

        }

      }

      break;

    }

   

    if(servo_value[0] <= BOTTOM_SERVO_MIN)

    {

      servo_move_angle = 1;

      servo_value[0] = BOTTOM_SERVO_MIN;

    }

    else if(servo_value[0] >= BOTTOM_SERVO_MAX)

    {

      servo_move_angle = -1;

      servo_value[0] = BOTTOM_SERVO_MAX;

    }

   

    servo_value[0] += servo_move_angle;

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

    delay(times);

  }

  if(dir == 1)

  {

    Left();

    delay(500);

    Stop();

  }

  else if(dir == 2)

  {

    Right();

    delay(500);

    Stop();

  }

}


void Forward()

{

  analogWrite(5,120);

  analogWrite(6,0);

  analogWrite(9,120);

  analogWrite(10,0);

}


void Left()

{

  analogWrite(5,105);

  analogWrite(6,0);

  analogWrite(9,0);

  analogWrite(10,105);

}


void Right()

{

  analogWrite(5,0);   

  analogWrite(6,105);

  analogWrite(9,105);

  analogWrite(10,0);

}


void Stop()

{

  digitalWrite(5,HIGH);

  digitalWrite(6,HIGH);

  digitalWrite(9,HIGH);

  digitalWrite(10,HIGH);  

}

② 上位机例程

   下面提供一个可以实现双轮智能小车追踪蓝色小球的参考例程(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

    {

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

        [DllImport("Camshift_DLL.dll", CharSet = CharSet.Ansi)]

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

                                                                                ref int xpos, //检测框中心X坐标

                                                                                ref int ypos, //检测框中心Y坐标

                                                                                ref int td);   //检测区域对角线长度


        //定义窗口大小

        int cap_w = 320, cap_h = 240;

        //跟踪物体中心 x, y 坐标值

        int x = 0, y = 0, d = 0;

        //定义命令变量

        string CMD_FORWARD = "", CMD_TURN_LEFT = "", CMD_TURN_RIGHT = "", CMD_STOP = "", CMD_LOST = "";

        //结构体

        public struct Boundaries

        {

            public int x_left;

            public int x_right;

            public int y_up;

            public int y_down;

            public int d_min;

            public int d_max;

        }

        Boundaries boundaries = new Boundaries();


        public MainWindow()

        {

            InitializeComponent();

        }


        private void Window_Loaded(object sender, RoutedEventArgs e)

        {

            GetIni();

            SetPosition();

            CmdInit();

            StructInit();

        }


        //变量初始化

        private void CmdInit()

        {

            CMD_FORWARD = "F";

            CMD_TURN_LEFT = "L";

            CMD_TURN_RIGHT = "R";

            CMD_STOP = "S";

            CMD_LOST = "N";

        }


        //结构体初始化

        private void StructInit()

        {

            boundaries.x_left = 120;

            boundaries.x_right = 240;

            boundaries.y_up = 80;

            boundaries.y_down = 160;

            boundaries.d_min = 50;

            boundaries.d_max = 150;

        }


        //获取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, int _d)

        {

            try

            {

                //判断转动方向

                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 (_d > boundaries.d_min && _d < boundaries.d_max)

                {

                    SendData(CMD_FORWARD);

                }

                else if ((_x > boundaries.x_left && _x < boundaries.x_right)&&

                        (_d >= 0 && _d <= boundaries.d_min ))

                {

                    SendData(CMD_LOST);

                }

                else

                {

                    SendData(CMD_STOP);

                }

            }

            catch { };

        }


        //物体位置初始化

        private void SetPosition()

        {

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

            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, int d)

        {

            LineDetect(x, y, d);


            Canvas.SetLeft(objEllipse, x);

            Canvas.SetTop(objEllipse, y);


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

        }


        //线程函数

        private void ThreadCapShow()

        {

            try

            {

                while (true)

                {

                    this.Dispatcher.Invoke(

                        new Action(

                            delegate

                            {

                                string ip = this.videoAddress.Text;

                                Camshift(ip, ref x, ref y, ref d);

                                PositionUpdate(x - 15, y - 15, d);

                            }

                            ));

                }


            }

            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/561913.html

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

相关文章

CRM系统软件不好用有哪些原因?如何选择?

CRM系统的实施也会出现无法落地使用的情况&#xff0c;让CRM系统软件名存实亡。这不仅仅只是个例&#xff0c;很多企业即使投入了很大成本&#xff0c;也不能让CRM系统真正用起来。CRM系统软件用不起来&#xff0c;可以排查这三个原因&#xff0c;教你解决&#xff01; 1.操作…

简单粗暴实现el-input只允许输入数字

<el-input input"phoneNumberphoneNumber.replace(/[^0-9.]/g,)" v-model"phoneNumber" maxlength"11" > </el-input> 如果加入type"number"&#xff0c;会在输入框右侧出现这个恶心的东西 尽管可以使用样式来屏蔽掉 …

基于ArcGIS Pro、Python、USLE、R、INVEST模型等多技术融合的生态系统服务构建生态安全格局

目录 基于ArcGIS Pro、Python、USLE、INVEST模型等多技术融合的生态系统服务构建生态安全格局 第一章 生态安全评价理论及方法介绍 第二章 平台基础 第三章 数据获取与清洗 第四章 基于USLE模型的土壤侵蚀评价 第五章 基于风蚀修正模型的防风固沙功能评估 第六章 水源涵…

联想集团财报:收入持续下滑,联想集团财务前景已恶化

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 联想集团2023财年第三季度财务业绩回顾 联想集团&#xff08;00992&#xff09;于2023年2月16日盘后公布了该公司2023财年第三季度的财报。 财报显示&#xff0c;联想集团的收入已经从2022财年第三季度的201.27亿美元下降到…

西门子PLC如何实现1主多从网口无线通讯

常规来说&#xff0c;多台plc要实现以太网无线连接&#xff0c;首先要先确定以太网线必须正确连接&#xff0c;并建立物理连接。然后需要在PLC端设置好IP地址&#xff0c;以使不同PLC以相同协议可以实现通信交流。最后是建立PLC端数据采集及交换系统&#xff0c;要求在PLC端设置…

一篇必读的物联网平台物模型开发指南,为你解锁未来科技趋势

《高并发系统实战派》-- 值得拥有 文章目录 一、什么是物模型&#xff1f;二、为什么要设计物模型&#xff1f;三、如何设计物模型&#xff1f;设备属性的设计设备服务的设计设备事件的设计 四、物模型案例五、不设计物模型会有什么影响&#xff1f;六、总结 设计物模型可以使物…

热烈欢迎CSDN副总裁邹欣老师入驻知识星球

重磅消息 CSDN 副总裁 邹欣 老师成功入驻知识星球 —— 英雄算法联盟&#xff0c;成为合伙人之一。 这将是未来几年内&#xff0c;IT界最震撼的一次合作&#xff01;我相信就算现在不是&#xff0c;将来必定是&#xff01; 当然&#xff0c;这对我来说也是一种极大的鼓舞&#…

C语言实现“队列“

&#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ &#x1f43b;推荐专栏: &#x1f354;&#x1f35f;&#x1f32f;C语言进阶 &#x1f511;个人信条: &#x1f335;知行合一 &#x1f349;本篇简介:>:分享数据结构之C语言实现"队列".各个接口分别分析…

回归预测 | MATLAB实现SSA-DELM和DELM麻雀算法优化深度极限学习机多输入单输出回归预测对比

回归预测 | MATLAB实现SSA-DELM和DELM麻雀算法优化深度极限学习机多输入单输出回归预测对比 目录 回归预测 | MATLAB实现SSA-DELM和DELM麻雀算法优化深度极限学习机多输入单输出回归预测对比效果一览基本介绍模型描述程序设计参考资料 效果一览 基本介绍 Matlab实现SSA-DELM和D…

突破极限:YOLO9000 论文解读 - 构建更好、更快、更强大的实时检测系统

YOLOv2 论文全篇完整翻译 摘要 我们介绍了YOLO9000&#xff0c;这是一种先进的、实时的目标检测系统&#xff0c;可以检测超过9000个物体类别。首先&#xff0c;我们对YOLO检测方法进行了各种改进&#xff0c;包括新颖的方法和借鉴自先前工作的方法。改进后的模型YOLOv2在标准…

港科夜闻|叶玉如校长在大湾区科学论坛主论坛发表「为应对人口老龄化贡献大湾区力量」主旨演讲...

关注并星标 每周阅读港科夜闻 建立新视野 开启新思维 1、叶玉如校长在大湾区科学论坛主论坛发表「为应对人口老龄化贡献大湾区力量」主旨演讲。她指出&#xff0c;中国已成为世界上老年人口最多、老龄化速度最快的国家之一&#xff0c;预计到2025年&#xff0c;65岁及以上人口3…

亚马逊云科技:点燃云原生数据库创新的星星之火

‍数据智能产业创新服务媒体 ——聚焦数智 改变商业 近10年&#xff0c;全球数据库市场加速变革&#xff0c;云数据库尤其是云原生数据库成为整个数据库市场的关键变量。某种程度上&#xff0c;亚马逊云科技作为全球云原生数据库的领导者&#xff0c;具有行业风向标的价值。 近…

2023.5.19Redis和MongoDB安装

四种数据库设置 hbase(main):001:0> create student,Sname,Ssex,Sage,Sdept,course Created table student Took 2.4760 seconds > Hbase::Table - student hbase(main):002:0> list TABLE …

性能测试——系统性能数据收集和Prometheus 监控系统部署应用实战

系统性能数据收集和Prometheus 监控系统部署应用实战 一、部署性能监控工具 node-exporter1、拉取镜像2、启动容器&#xff1a;3、配置prometheus.yml4、重启prometheus系统&#xff0c;检查node-exporter targets数据是否显示正常 二、Prometheus 监控系统部署应用实战1、实战…

盘点IntelliJ IDEA 中的“快速”功能,你知道几个?

IntelliJ IDEA&#xff0c;是java编程语言开发的集成环境。IntelliJ在业界被公认为最好的java开发工具&#xff0c;尤其在智能代码助手、代码自动提示、重构、JavaEE支持、各类版本工具(git、svn等)、JUnit、CVS整合、代码分析、 创新的GUI设计等方面的功能是非常强大的。 Int…

HTML+CSS实训——Day02——仿一个网易云音乐的登陆界面

前言 今天要继续完成我们的音乐软件了&#xff0c;昨天写完了封面&#xff0c;今天该完成开屏广告和登陆界面了。 登陆界面代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-C…

短视频矩阵源码核心研发接口

1.短视频矩阵源码涉及了多种接口&#xff0c;包括但不限于视频上传、视频播放、视频推荐、用户管理、评论管理、点赞管理等。其中视频上传接口用于将用户上传的视频数据进行处理和存储&#xff1b;视频播放接口用于向用户展示视频内容并提供播放操作&#xff1b;视频推荐接口用…

springboot 集成 Swagger2(速通)

目录 1. 概述2. 案例 13. UI 的简单使用4. 简单配置 Docket 对象1. 配置文档的描述信息2. 定义包扫描规则 5. 指定接口不生成文档1. 自定义注解2. 路径匹配 6. 常用注解 1. 概述 简单理解——代写接口文档的框架&#xff0c;可跟随接口修改实时更新。 Open API 格式&#xff…

【服务器】安卓手机使用Termux搭建web服务

Yan-英杰的主页 悟已往之不谏 知来者之可追 C程序员&#xff0c;2024届电子信息研究生 目录 概述 1.搭建apache 2.安装cpolar内网穿透 3.公网访问配置 4.固定公网地址 5.添加站点 概述 Termux是一个Android终端仿真应用程序&#xff0c;用于在 Android 手机上搭建一个…

从C语言到C++_12(string相关OJ题)(leetcode力扣)

上一篇已经讲了string类的接口函数&#xff0c;然后根据查文档刷了牛客和力扣58最后一个单词的长度&#xff0c; 还有力扣415字符串相加&#xff0c;这篇继续跟着查文档来刷力扣题&#xff0c;体会C刷题的方便。 目录 917. 仅仅反转字母 - 力扣&#xff08;LeetCode&#xf…