1. 任务描述

在机器人小车(R023d)上搭载摄像头,摄像头采集图像信息并通过WiFi将信息传递给PC端,然后PC端使用OpenCV对摄像头读取到的视频进行灰度化、高斯滤波、腐蚀、膨胀等处理,使图像分为黑白两色。PC端进行图像信息处理并将处理结果传递为下位机,下位机接收上位机处理的图像信息结果后便会控制小车相应运动,小车运动包含前进、左转、右转、停止。

2. 电子硬件

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

主控板 Basra(兼容Arduino Uno)
扩展板 Bigfish2.1
电池 7.4V锂电池

通信

2510通信转接板
WiFi路由器
其它 摄像头x1、计算机x1

3. 功能实现

视觉小车巡黑线工作原理:

(1) 摄像头采集图像信息;

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

(3) 在 PC 端使用 OpenCV 对摄像头读取到的视频进行灰度化、高斯滤波、腐蚀、膨胀等处理,使图像分为黑白两色,采用 RGB 颜色模型作为黑白颜色判断;

(4) 将图像对称分成左右两半,分别判断左、右计算检测在显示的摄像范围内的黑色像素区域所占比例=黑色像素范围/显示的摄像范围;

(5) 比较两侧黑色像素区域所占比例大小确定前进方向,如果左侧比例大于右侧,则小车左偏离,进行右转;

(6) PC端进行图像信息处理,将处理结果传递为下位机,下位机控制小车进行相应的运动;

3.1硬件连接

接线说明:

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

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

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

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

3.2示例程序

编程环境:Arduino 1.8.19

① 下位机例程:

下位机接收上位机处理的图像信息结果控制小车相应运动,小车运动包含前进、左转、右转、停止。

参考例程代码(car.ino)如下:

/*------------------------------------------------------------------------------------版权说明:Copyright 2023 Robottime(Beijing) Technology Co., Ltd. All Rights Reserved.Distributed under MIT license.See file LICENSE for detail or copy athttps://opensource.org/licenses/MITby 机器谱 2023-02-02 https://www.robotway.com/-----------------------------------------------------------------------------------/*wift car:2019/08/19:JNleft: 9, 5;right: 10, 6;  */const String FORWARD = "F";const String BACK = "B";const String LEFT = "L";const String RIGHT = "R";const String STOP = "S";int speed_left = 41;int speed_right = 41;void setup() {Serial.begin(9600);pinMode(5, OUTPUT);pinMode(6, OUTPUT);pinMode(9, OUTPUT);pinMode(10, OUTPUT);Stop();delay(1000);}void loop() {String data = SerialRead();//if(data != ""){   if(data == FORWARD)Forward();else if(data == BACK)Back();else if(data == LEFT)Left();else if(data == RIGHT)Right();   else if(data == STOP)Stop();// }}String SerialRead(){String str;while(Serial.available()){str += char(Serial.read());}return str;}void Forward(){analogWrite(9, speed_left);analogWrite(5, 0);analogWrite(6, 0);analogWrite(10, speed_right);}void Back(){analogWrite(9, 0);analogWrite(5, speed_left);analogWrite(6, speed_right);analogWrite(10, 0);}void Left(){analogWrite(9, 0);analogWrite(5, speed_left);analogWrite(6, 0);analogWrite(10, speed_right);}void Right(){analogWrite(9, speed_left);analogWrite(5, 0);analogWrite(6, speed_right);analogWrite(10, 0);}void Stop(){analogWrite(9, speed_left);analogWrite(5, speed_left);analogWrite(6, speed_right);analogWrite(10,speed_right);}

② 上位机例程:

上位机(Visual Studio 2015.net下配置OpenCV环境)进行图像信息处理。下面提供一个参考例程(MainWindow.xaml.cs),大家可尝试根据实验效果改写。

/*******************************************************************************************版权说明:Copyright 2023 Robottime(Beijing) Technology Co., Ltd. All Rights Reserved.Distributed under MIT license.See file LICENSE for detail or copy athttps://opensource.org/licenses/MITby 机器谱 2023-02-02 https://www.robotway.com/---------------------------------------------------------------------------------------using System;using System.IO;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.Media.Animation;using System.Threading;using OpenCvSharp;using System.Drawing;using System.Drawing.Imaging;using System.Net;using System.Net.Sockets;namespace Tracking_Car{/// <summary>/// Tracking_Car/// </summary>public partial class MainWindow : System.Windows.Window{//定义视频,控制地址以及控制端口变量static string CameraIp = "http://192.168.8.1:8083/?action=stream";static string ControlIp = "192.168.8.1";static string Port = "2001";//定义上位机发送的控制命令变量//定义命令变量string CMD_FORWARD = "", CMD_TURN_LEFT = "", CMD_TURN_RIGHT = "", CMD_STOP = "";/** 指针角度对应各颜色* 25 -> 红色* 90 -> 绿色* 150 -> 蓝色*/int ANGLE_LEFT = 0;int ANGLE_GO = 0;int ANGLE_RIGHT = 0;//黑色像素在左右两侧所占比例double numOfleft = 0.0;double numOfright = 0.0;//创建视频图像实例VideoCapture capture = new VideoCapture(CameraIp); //图像大小:宽度 X 长度 = 160 X 120;Mat frame = new Mat();   //存储视频每一帧图像像素Mat result = new Mat(); //存储二值化图像static byte[] kernelValues = { 0, 1, 0, 1, 1, 1, 0, 1, 0 }; // cross (+)Mat kernel = new Mat(3, 3, MatType.CV_8UC1, kernelValues);//图像中心线坐标int x1, y1, x2, y2;//窗口面积float area;//视频显示切换变量Boolean isChange = false;//循迹开始开关变量Boolean isBegin = false;public MainWindow(){InitializeComponent();}private void Window_Loaded(object sender, RoutedEventArgs e){Assignment();}//变量赋值函数private void Assignment(){ANGLE_LEFT = 25;ANGLE_GO = 90;ANGLE_RIGHT = 150;rateLeft.Height = 10;rateRight.Height = 10;x1 = 80;y1 = 0;x2 = x1;y2 = 120;area = 160 * 120 / 2;CMD_FORWARD = "F";CMD_TURN_LEFT = "L";CMD_TURN_RIGHT = "R";CMD_STOP = "S";}/// <summary>/// MatToBitmap(Mat image)/// </summary>public static Bitmap MatToBitmap(Mat image){return OpenCvSharp.Extensions.BitmapConverter.ToBitmap(image);}/// <summary>/// BitmapToBitmapImage(System.Drawing.Bitmap bitmap)/// </summary>public static BitmapImage BitmapToBitmapImage(Bitmap bitmap){using (MemoryStream stream = new MemoryStream()){bitmap.Save(stream, ImageFormat.Png); //格式选Bmp时,不带透明度stream.Position = 0;BitmapImage result = new BitmapImage();result.BeginInit();// According to MSDN, "The default OnDemand cache option retains access to the stream until the image is needed."// Force the bitmap to load right now so we can dispose the stream.result.CacheOption = BitmapCacheOption.OnLoad;result.StreamSource = stream;result.EndInit();result.Freeze();return result;}}//颜色指示动画函数int angelCurrent = 0;private void ColorIndicate(int where){RotateTransform rt = new RotateTransform();rt.CenterX = 130;rt.CenterY = 200;this.indicatorPin.RenderTransform = rt;double timeAnimation = Math.Abs(angelCurrent - where) * 5;DoubleAnimation da = new DoubleAnimation(angelCurrent, where, new Duration(TimeSpan.FromMilliseconds(timeAnimation)));da.AccelerationRatio = 0.8;rt.BeginAnimation(RotateTransform.AngleProperty, da);switch (where){case 25:dirDisplay.Content = "左转";break;case 90:dirDisplay.Content = "前进";break;case 150:dirDisplay.Content = "右转";break;default:dirDisplay.Content = "方向指示";break;}angelCurrent = where;}//检测函数private void ColorDetect() {//将摄像头RGB图像转化为灰度图,便于后续算法处理Mat gray = frame.CvtColor(ColorConversionCodes.BGR2GRAY);//进行高斯滤波Mat binary = gray.Threshold(0, 255, ThresholdTypes.Otsu | ThresholdTypes.Binary);//闭运算,先膨胀后腐蚀,消除小型黑洞Cv2.Dilate(binary, binary, null);Cv2.Erode(binary, binary, kernel);result = binary.Clone();result.Line(new OpenCvSharp.Point(x1, y1), new OpenCvSharp.Point(x2, y2), new Scalar(255, 255, 255), 1);float rateOfleft = 0, rateOfRight = 0;var indexer = result.GetGenericIndexer<Vec3b>();for (int i = 0; i < result.Rows; i++) {for (int j = 0; j < result.Cols; j++) {int B = indexer[i, j][0];int G = indexer[i, j][1];int R = indexer[i, j][2];if (B == 0 && G == 0 && R == 0) {if (j <= x1) {numOfleft++;}else{numOfright++;}}}}rateOfleft = (float)(numOfleft) / area * 100;rateOfRight = (float)(numOfright) / area * 100;rateLeft.Height = rateOfleft;rateRight.Height = rateOfRight;numOfleft = 0;numOfright = 0;}//命令发送函数void SendData(string data){try{IPAddress ips = IPAddress.Parse(ControlIp.ToString());//("192.168.8.1");IPEndPoint ipe = new IPEndPoint(ips, Convert.ToInt32(Port.ToString()));//把ip和端口转化为IPEndPoint实例Socket c = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//创建一个Socketc.Connect(ipe);//连接到服务器byte[] bs = Encoding.ASCII.GetBytes(data);c.Send(bs, bs.Length, 0);//发送测试信息c.Close();}catch (Exception e){MessageBox.Show(e.Message);}}//方向指示更新及命令发送private void CommandSend() {double l = rateLeft.Height;double r = rateRight.Height;if (isBegin) {if (Math.Abs(l - r) < 20)   //两侧黑色轨迹基本相同,前进{ColorIndicate(ANGLE_GO);SendData(CMD_FORWARD);}else if ((l - r) < -50)     //左侧黑色轨迹小于右侧,右转{ColorIndicate(ANGLE_RIGHT);SendData(CMD_TURN_RIGHT);}else if ((l - r) > 50)      //右侧黑色轨迹小于左侧,左转{ColorIndicate(ANGLE_LEFT);SendData(CMD_TURN_LEFT);}}}//视频显示函数private void ThreadCapShow(){while (true){try{capture.Read(frame); // same as cvQueryFrameif (frame.Empty())break;this.Dispatcher.Invoke(new Action(delegate{if (isChange){//检测图像左右两侧黑色像素所占的比例,并显示图像ColorDetect();originImage.Source = BitmapToBitmapImage(MatToBitmap(result));CommandSend();result = null;}else{originImage.Source = BitmapToBitmapImage(MatToBitmap(frame));}}));//Cv2.WaitKey(100);//bitimg = null;}catch { }}}//加载视频private void loadBtn_Click(object sender, RoutedEventArgs e){if (originImage.Source != null) return;Thread m_thread = new Thread(ThreadCapShow);m_thread.IsBackground = true;m_thread.Start();}//切换视频显示,显示检测结果private void changeBtn_Click(object sender, RoutedEventArgs e){if (!isChange){isChange = true;changeBtn.Content = "返回";}else{isChange = false;changeBtn.Content = "切换";//指针角度归零ColorIndicate(0);rateLeft.Height = 10;rateRight.Height = 10;result = null;}}//循迹开始private void bgeinBtn_Click(object sender, RoutedEventArgs e){isBegin = true;}//循迹停止private void stopBtn_Click(object sender, RoutedEventArgs e){isBegin = false;SendData(CMD_STOP);}}}

4. 资料下载

​资料内容:
​①【R023】-视觉循迹-程序源代码
​②【R023】-视觉循迹-样机3D文件
​资料下载地址:https://www.robotway.com/h-col-113.html

想了解更多机器人开源项目资料请关注 机器谱网站

如何让小型双轮差速底盘实现视觉循迹功能相关推荐

  1. 小型双轮差速底盘三灰度循迹功能的实现

    1. 功能说明 在小型双轮差速底盘样机前方安装3个 灰度传感器 ,实现机器人沿下图所指定的跑道路线进行运动的效果. 2. 使用样机 本实验使用的样机为R023样机. 3. 功能实现 3.1 电子硬件 ...

  2. 小型双轮差速底盘实现红外避障功能

    1. 功能说明 在R023e机器人车体上安装1个近红外传感器,实现机器人小车避障功能. 2. 电子硬件 在这个示例中,我们采用了以下硬件,请大家参考: 主控板 Basra主控板(兼容Arduino U ...

  3. 小型双轮差速底盘实现触须避障

    1. 功能说明 在R023d机器人车体上安装2个 触须传感器 ,实现机器人小车避障功能. 2. 电子硬件 在这个示例中,我们采用了以下硬件,请大家参考: 主控板 Basra主控板(兼容Arduino ...

  4. 《动手学机器人学》7.4机器人运动学介绍|机械臂运动学|两轮差速底盘运动学|轮式里程计

    本系列教程作者:小鱼 公众号:鱼香ROS QQ交流群:139707339 教学视频地址:小鱼的B站 完整文档地址:鱼香ROS官网 版权声明:如非允许禁止转载与商业用途. 7.4 机器人运动学介绍 机器 ...

  5. 使用MATLAB完成一个双轮差速驱动的移动机器人“走8字”的仿真,并生成视频

    使用MATLAB完成一个双轮差速驱动的移动机器人"走8字"的仿真,,并生成视频 (一)任务目标      完成一个双轮差速驱动的移动机器人"走8字"的仿真. ( ...

  6. 基于PID调节的两轮自平衡小车的循迹控制

    基于PID调节的两轮自平衡小车的循迹控制   硬件电路篇 小车主控芯片使用飞思卡尔公司产的K60. 电源模块 车体电路使用两种电压,分别为3.3v和5v供电.车体使用7.2V的锂电池供电,为提供电路所 ...

  7. 制作一个小型双节履带底盘【内附资料下载链接】

    1.运动功能说明 双节履带车可以通过两个驱动轮的差速运动来实现前进.后退.原地转向.大半径转向等基本行驶功能,并可通过舵机关节模块进行小臂的抬起和落下.通过底盘运动与小臂运行的结合,实现上台阶.通过坑 ...

  8. ROS学习笔记6 URDF建立机器人模型(以双轮差速小车为例)

    URDF建立机器人模型 一.准备工作 一.搭建小车底盘模型 1.小车底盘 2.左右驱动轮 3.前后万向轮 4.launch启动文件 5.效果展示 二.摄像头仿真模型 1.添加摄像头模型 2.launc ...

  9. ROS中两轮差速底盘给定线速度和角速度值的合法性检查

    d是两轮的距离 VL是左轮的线速度 VR是右轮的线速度 V是两轮连线中心的线速度 是两轮连线中心的角速度(图中未标出) r是0时两轮连线中心弧形轨迹的半径 由于电机性能的限制,左右两轮的速度VL.VR ...

最新文章

  1. Facebook的「下一代 AI 计算平台」长什么样子?
  2. OpenCV alpha(权因子) 融合举例
  3. MySQL在多表上创建视图
  4. bat脚本注释多行_cmd批处理常用符号详解
  5. android bitmap转图片_Android 这些 Drawable 你都会用吗?
  6. gcc:编译 expected declaration specifiers or ‘...’ before
  7. 防不胜防!微信借钱语音确认仍被骗:我可真是太难了
  8. 4.7 Spark SQL 数据分析流程
  9. 八十年代的计算机游戏,儿时小霸王的记忆 八十年代最伟大的二十款游戏
  10. 小米发布会之文案错误:大哥你先处罚自己!再处罚相关高管!
  11. l360清零软件无响应_爱普生Epson L360 清零软件
  12. support vector regression(SVR)支持向量回归
  13. 最简单的STM32入门教程----闪烁LED
  14. 高级计量经济学及stata应用_推荐使用的计量经济学教材
  15. 《亲密关系》读后感_设计的直觉和亲密感
  16. 公交路线查询数据接口简单介绍
  17. Android修行手册 - TextureView和SurfaceView的属性方法以及示例
  18. Canvas 绘制点线相交
  19. 毕业设计说明书(论文)结构-系统设计方面
  20. 使用rufus制作Windows Server 2012 R2 U盘_wentfar·tsao

热门文章

  1. 编程加载族文件(Revit2012)
  2. 无法打开项目文件。 无法找到 .NET SDK。请检查确保已安装此项且 global.json 中指定的版本(如有)与所安装的版本相匹配
  3. nodejs中流操作的优势和分类
  4. Python知识训练-序列结构
  5. C# DataTable和List之间相互转换
  6. echarts地图散点热力图1
  7. 用克拉默法则求非齐次线性方程组
  8. 精彩回顾:终于明白阿里百度为什么拿WaitNotify通知机制考察求职者了
  9. DigiCert SSL证书怎么样?
  10. SAP 物料号码变更 会计科目变更_v0.9