极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 2325|回复: 0

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

[复制链接]
发表于 2023-5-22 10:57:41 | 显示全部楼层 |阅读模式
本帖最后由 机器谱 于 2023-5-22 10:57 编辑

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


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网络。下位机接收上位机处理的图像信息结果控制舵机云台相应运动,云台跟随目标物体运动。
  1. /*------------------------------------------------------------------------------------

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

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

  4.            https://opensource.org/licenses/MIT

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

  6.    ------------------------------*/

  7. #include <Servo.h>

  8. #define BOTTOM_SERVO_MIN 10

  9. #define BOTTOM_SERVO_MAX 175

  10. #define TOP_SERVO_MIN 85

  11. #define TOP_SERVO_MAX 175

  12. const String CMD_UP = "U";

  13. const String CMD_DOWN = "D";

  14. const String CMD_LEFT = "L";

  15. const String CMD_RIGHT = "R";

  16. Servo myServo[2];

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

  18. int port0 = 4;

  19. int port1 = 7;

  20. int servo_move_angle = 1;

  21. void setup()

  22. {

  23.    Serial.begin(9600);

  24.    ServoInit();

  25.    delay(1000);

  26. }

  27. void loop()

  28. {

  29.    String s = SerialRead();

  30.    

  31.    if(s != "")

  32.    {

  33.     if(s == CMD_UP)

  34.       ServoAdjust(port1, -servo_move_angle);

  35.     else if(s == CMD_DOWN)

  36.       ServoAdjust(port1, servo_move_angle);

  37.     else if(s == CMD_LEFT)

  38.       ServoAdjust(port0, -servo_move_angle);

  39.     else if(s == CMD_RIGHT)

  40.       ServoAdjust(port0, servo_move_angle);

  41.    }

  42. }

  43. String SerialRead()

  44. {

  45.    String str = "";

  46.    while(Serial.available())

  47.    {

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

  49.    }

  50.    return str;

  51. }

  52. void ServoInit()

  53. {

  54.    myServo[0].attach(port0);

  55.    myServo[1].attach(port1);

  56.    

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

  58.    {

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

  60.    }

  61. }

  62. void ServoAdjust(int which, int where)

  63. {

  64.    switch(which)

  65.    {

  66.     case 4:

  67.       servo_value[0] += where;

  68.      

  69.       if(servo_value[0] <= BOTTOM_SERVO_MIN)

  70.         servo_value[0] = BOTTOM_SERVO_MIN;

  71.       else if(servo_value[0] >= BOTTOM_SERVO_MAX)

  72.         servo_value[0] = BOTTOM_SERVO_MAX;

  73.      

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

  75.       break;

  76.     case 7:

  77.       servo_value[1] += where;

  78.      

  79.       if(servo_value[1] <= TOP_SERVO_MIN)

  80.         servo_value[1] = TOP_SERVO_MIN;

  81.       else if(servo_value[1] >= TOP_SERVO_MAX)

  82.         servo_value[1] = TOP_SERVO_MAX;

  83.      

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

  85.       break;

  86.     default:

  87.       break;

  88.    }

  89. }
复制代码

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

  2. using System.Collections.Generic;

  3. using System.Linq;

  4. using System.Text;

  5. using System.Threading.Tasks;

  6. using System.Windows;

  7. using System.Windows.Controls;

  8. using System.Windows.Data;

  9. using System.Windows.Documents;

  10. using System.Windows.Input;

  11. using System.Windows.Media;

  12. using System.Windows.Media.Imaging;

  13. using System.Windows.Navigation;

  14. using System.Windows.Shapes;

  15. using System.Windows.Forms;

  16. using System.Runtime.InteropServices;

  17. using System.Threading;

  18. using System.Net;

  19. using System.Net.Sockets;


  20. namespace Project

  21. {

  22.     /// <summary>

  23.     /// 形状跟踪,球

  24.     /// </summary>

  25.     public partial class MainWindow : Window

  26.     {

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

  28.         [DllImport("HoughCircles_DLL")]

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

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

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


  32.         //定义窗口大小

  33.         int cap_w = 320, cap_h = 240;

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

  35.         int x = 0, y = 0;

  36.         //定义命令变量

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

  38.         //结构体

  39.         public struct Boundaries

  40.         {

  41.             public int x_left;

  42.             public int x_right;

  43.             public int y_up;

  44.             public int y_down;

  45.         }

  46.         Boundaries boundaries = new Boundaries();


  47.         public MainWindow()

  48.         {

  49.             InitializeComponent();

  50.         }


  51.         private void Window_Loaded(object sender, RoutedEventArgs e)

  52.         {

  53.             GetIni();

  54.             SetPosition();

  55.             CmdInit();

  56.             StructInit();

  57.         }


  58.         //变量初始化

  59.         private void CmdInit()

  60.         {

  61.             CMD_UP = "U";

  62.             CMD_DOWN = "D";

  63.             CMD_TURN_LEFT = "L";

  64.             CMD_TURN_RIGHT = "R";

  65.         }


  66.         //结构体初始化

  67.         private void StructInit()

  68.         {

  69.             boundaries.x_left = 100;

  70.             boundaries.x_right = 200;

  71.             boundaries.y_up = 80;

  72.             boundaries.y_down = 160;

  73.         }


  74.         //获取ini配置文件信息

  75.         private void GetIni()

  76.         {

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

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

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

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

  81.         }


  82.         //修改配置

  83.         private void setBtn_Click(object sender, RoutedEventArgs e)

  84.         {

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

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

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


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

  89.             //this.Close();

  90.         }


  91.         //命令发送函数

  92.         void SendData(string data)

  93.         {

  94.             try

  95.             {

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

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

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


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


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

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

  102.                 c.Close();

  103.             }

  104.             catch (Exception e)

  105.             {

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

  107.             }

  108.         }


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

  110.         private void LineDetect(int _x, int _y)

  111.         {

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

  113.             {

  114.                 SendData(CMD_TURN_LEFT);

  115.             }

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

  117.             {

  118.                 SendData(CMD_TURN_RIGHT);

  119.             }

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

  121.             {

  122.                 SendData(CMD_DOWN);

  123.             }

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

  125.             {

  126.                 SendData(CMD_UP);

  127.             }

  128.         }


  129.         //物体位置初始化#FFACAAAA

  130.         private void SetPosition()

  131.         {

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

  133.             objEllipse.Height = 30;

  134.             objEllipse.Width = 30;

  135.             objEllipse.Fill = color;


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

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


  138.             Canvas.SetLeft(objEllipse, left_distance);

  139.             Canvas.SetTop(objEllipse, top_distance);

  140.         }


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

  142.         private void PositionUpdate(int x, int y)

  143.         {

  144.             LineDetect(x, y);


  145.             Canvas.SetLeft(objEllipse, x);

  146.             Canvas.SetTop(objEllipse, y);


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

  148.         }


  149.         //线程函数

  150.         private void ThreadCapShow()

  151.         {

  152.             try

  153.             {

  154.                 while (true)

  155.                 {

  156.                     this.Dispatcher.Invoke(

  157.                         new Action(

  158.                             delegate

  159.                             {

  160.                                 string ip = this.videoAddress.Text;

  161.                                 HoughCircles(ip, ref x, ref y);

  162.                                 PositionUpdate(x - 15, y - 15);

  163.                             }

  164.                             ));

  165.                 }


  166.             }

  167.             catch { };

  168.         }


  169.         //打开跟踪窗口

  170.         private void openBtn_Click(object sender, RoutedEventArgs e)

  171.         {

  172.             try

  173.             {

  174.                 Thread m_thread = new Thread(ThreadCapShow);

  175.                 m_thread.IsBackground = true;

  176.                 m_thread.Start();

  177.             }

  178.             catch { };

  179.         }

  180.     }

  181. }
复制代码

4. 资料下载
资料内容:
①追踪球形目标-例程源代码
②追踪球形目标-样机3D文件
资料下载地址:https://www.robotway.com/h-col-126.html

想了解更多机器人开源项目资料请关注 机器谱网站 https://www.robotway.com

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-4-25 19:48 , Processed in 0.039767 second(s), 17 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表