赞
踩
任务概要
因为疫情原因,在家上网课。因为放假前完全没有想到会放如此长的‘假’,所以我把所有学习用的开发板、硬件、开发教程书籍都放在了学校实验室里,从而现在不但不能在家做实物,也不能去学校做实物的尴尬情形。随后因为一门课(计算机控制技术)改变了这种尴尬的情形。
张老师推荐我们使用Vrep进行机器人仿真,并且实现pid控制,于是乎我马上利用空闲时间研究了这款软件,做了机器人视觉巡线+pid调速。
在实现视觉巡线之前我提交了多次作业,从简单的灰度巡线到视觉巡线。
疫情让我使用V-rep仿真实现机器人视觉巡线+pid调速 |
V-REP 是机器人仿真器里的“瑞士军刀”:你不会发现一个比它拥有更多功能,特色或是更详尽应用编程接口的机器人仿真器:
• 跨平台 (Windows、MacOS、Linux)
• 六种编程方法 (嵌入式脚本、插件、附加组件、ROS节点、远程客户端应用编程接口、或自定义的解决方案)
• 七种编程语言 (C/C++、Python、Java、Lua、Matlab、Octave、和 Urbi)
• 超过400种不同的应用编程接口函数
• 100项ROS服务、30个发布类型、25个ROS订户类型、可拓展
• 4个物理引擎 (ODE, Bullet, Vortex, Newton)
• Integrated ray-tracer (POV-Ray)
• 完整的运动学解算器 (对于任何机构的逆运动学和正运动学)
• Mesh, octree, point cloud-网孔干扰检测
• Mesh, octree, point cloud-网孔最短距离计算
• 路径规划 (在2到6维中的完整约束、对于车式车辆的非完整约束)
• 嵌入图像处理的视觉传感器 (完全可拓展)
• 现实的接近传感器 (在检测区域中的最短距离计算)
• 嵌入式的定制用户接口、包括编辑器
• 完全集成的第四类Reflexxes运动库 + RRS-1 interface specifications
• 表面切削仿真
• 数据记录与可视化 (时距图、X/Y图或三维曲线)
• 整合图形编辑模式
• 支持水/气体喷射的动态颗粒仿真
• 带有拖放功能的模型浏览器 (在仿真中依旧可行)
• 多层 取消/重做、影像记录、油漆的仿真、详尽的文档等
接下来由我给大家一步步实现视觉检测和pid调速
我在下面会提供我的地图供大家下载使用。
Vision sensors, which can detect renderable entities(Renderable objects are objects that can be seen or detected by vision sensors), should be used over proximity sensors mainly when color, light or structure plays a role in the detection process. However, depending on the graphic card the application is running on, or on the complexity of the scene objects, vision sensors might be a little bit slower than proximity sensors. Following illustrates applications using vision sensors:
视觉传感器与摄像机都能显示场景中的图像但是也存在着区别(一个侧重视觉检测和处理,一个侧重场景显示):
视觉传感器可分为正交投影型和透视投影型,它们的视场形状不一样:
视觉传感器有近端剪切平面(near clipping plane)和远端剪切平面,使用剪切平面可以排除场景的一些几何体,只查看或渲染场景的某些部分。比近端剪切平面近或比远端剪切平面远的对象是不可视的。可以通过传感器属性对话框中的"Near / far clipping plane"设置剪切平面的位置。
透视模式下传感器的视场角(FOV)可以通过"Perspective angle [deg] / Orthographic size"来设置。Perspective angle: the maximum opening angle of the detection volume when the sensor is in perspective mode. 如下图所示设置视场角为60°,当X/Y分辨率一样时水平视场角和垂直视场角的大小相同。
正交模式下传感器的视场大小可以通过"Perspective angle [deg] / Orthographic size"来设置。Orthographic size: the maximum size (along x or y) of the detection volume when the sensor is not in perspective mode. 设置为Orthographic size为1m,X/Y方向分辨率为64/32,则X方向视场为1m,Y方向为0.5m,如下图所示:
使用视觉传感器的目的就是进行图像检测与处理,VREP中的视觉传感器在仿真过程中可以产生两种数据流:彩色图像(color image )和深度图(depth map)。我们可以通过API函数获取数据,然后遍历图像的每个像素进行处理,这样做灵活性很大,但是使用起来比较麻烦而且处理速度不够快。VREP提供了一种内部的filter来对图像进行处理(It is much more convenient (and fast!) to use the built-in filtering and triggering capabilities)。最简单的图像处理流程由3部分组成:输入→滤波→输出:
在Image processing and triggering对话框中可以添加30多种filter对图像进行快速处理,比如:
下面以均值滤波为例进行说明,3×3矩阵中各个分量设为1/9,则滤波器将会对原始图像每个像素周围的9个像素点取平均,对图像进行平滑,减小噪声:
复杂的图像处理流程可由多个部分组成,处理环节能完成4种基本的操作:
下图显示了图像处理流程中的各种缓存和相互之间的操作:
[Vision sensor buffers and operations between buffers]
The input image and input depth image are volatile buffers (易变缓存 i.e. normally automatically overwritten with new data at each simulation pass);The work image, buffer1 image and buffer2 image are persistent buffers (i.e. their content is not modified unless a component operates on them)
下面看一个比之前复杂点的例子,将原始图像边缘提取后旋转90°再叠加到原始图像上进行输出:先将要进行操作的work image保存到buffer 1中,然后对work image进行图像处理操作,接着将buffer 1叠加到work image上,最后将合成的图像进行输出。
我们来介绍一下这个函数:simExtRemoteApiStart,
功能描述:在指定端口上启动临时远程API服务器服务。当从模拟脚本启动时,服务将在模拟完成时自动结束
输入:
portNumber:安装服务器服务的端口。20000以上端口优先。为了使用共享内存,可以指定负端口号,而不是套接字通信。
maxPacketSize:套接字发送包的最大大小。确保将值保持在1300,除非客户端有不同的设置。
debug:如果为真,窗口将显示该端口上的数据流量。
preEnableTrigger:如果为真,将对来自客户机的同步触发信号预启用服务器服务。
输出:
num result:-1如果操作不成功。在未来的版本中,可能会有一个更差异化的回报价值
[有道词典翻译,服务于头疼英语的朋友]大致可以理解一下,这个函数通常输入一些端口等配置,来实现远程API与V-rep的临时通信(V-rep运行时才能通信!!!切记,划重点,要考)
以上完成了V-rep端的配置,下面介绍如何配置Python端。
笔者用的是Python 3.6,编译器是VS Studio
这些文件可以在Vrep的安装文件夹中找到,包括:
vrep.py
vrepConst.py
remoteApi.dll(win) remoteApi.dylib(mac) remoteApi.so(linux)
Vrep安装文件夹->programming->remoteApiBindings->
(1)->python->python-->vrep.py&vrepConst.py
(1)->lib->lib->(32/64 Bit)-->remoteApi.dll
将这些文件复制到VS定义的Project文件夹中,这样也省事,如图所示。
1.引入头文件
- import vrep
- import time
- import numpy as np
- import cv2
2.连接vrep
- # 连接vrep
- def connection(num):
- print('program start')
- vrep.simxFinish(-1) # 关掉之前的连接
- while True:
- clientId = vrep.simxStart("127.0.0.1", 19999, True, True, 5000, 5)#建立和服务器的连接
- if clientId != -1: #连接成功
- print('connect successfully')
- Get_Image(clientId)#获取传输的图像
- break
- else:
- time.sleep(0.2)
- print('connect failed')
- vrep.simxFinish(clientId)# 结束连接
- print('program ended')
3.获取服务端发来的图像
- def Get_Image(clientId):
- errorCode,visionSensorHandle = vrep.simxGetObjectHandle(clientId,'VS3',vrep.simx_opmode_oneshot_wait)#获取VS3的handle
- # 第一次获取数据无效
- errprCode,resolution,image = vrep.simxGetVisionSensorImage(clientId,visionSensorHandle,0,vrep.simx_opmode_streaming)
- time.sleep(0.1)
- #获取有效数据
- while True:
- errprCode,resolution,image = vrep.simxGetVisionSensorImage(clientId,visionSensorHandle,0,vrep.simx_opmode_buffer)
- sensorImage = np.array(image,dtype = np.uint8)
- sensorImage.resize([resolution[0],resolution[1],3])#整理矩阵
- cv2.imshow('sensorImage',sensorImage)#显示图像
- if cv2.waitKey(1)==27:
- break
4.首先运行Vrep(!!!)
5.再运行python文件(!!!)
6.运行结果
将整个画面分割为若干的检测区域,并给每个区域设定一个权值。
很容易理解, 距离越远的,重要性越高/越小, 根据自己的需求来设定不同的权值
最后算出来的偏移量带入pid进行计算,pid的教程网上有很多,就不再赘述了。
一文读懂PID控制算法(抛弃公式,从原理上真正理解PID控制)
pid.py
- import time
- class PositionalPID:
- def __init__(self, P, I, D):
- self.Kp = P
- self.Ki = I
- self.Kd = D
-
- self.SystemOutput = 0.0#系统输出值
- self.ResultValueBack = 0.0
- self.PidOutput = 0.0#PID控制器输出
- self.PIDErrADD = 0.0
- self.ErrBack = 0.0
- #设置一阶惯性环节系统 其中InertiaTime为惯性时间常数
- def SetInertiaTime(self, InertiaTime,SampleTime):
- self.SystemOutput = (InertiaTime * self.ResultValueBack + SampleTime * self.PidOutput) / (SampleTime + InertiaTime)
- self.ResultValueBack = self.SystemOutput
- #设置PID控制器参数
- def SetStepSignal(self,StepSignal):
- Err = StepSignal - self.SystemOutput
- KpWork = self.Kp * Err
- KiWork = self.Ki * self.PIDErrADD
- KdWork = self.Kd * (Err - self.ErrBack)
- self.PidOutput = KpWork + KiWork + KdWork
- self.PIDErrADD += Err
- self.ErrBack = Err
use_pid()
- def use_pid(P, I, D,signal1):
- PositionalPid = PID.PositionalPID(P, I, D)
- PositionalPid.SetStepSignal(signal1)
- return PositionalPid.PidOutput
只适用于单条线, 如果是多条线,就不能识别
如何识别直角?
问题其实还有很多, 这个算法比较简单, 但是适用的情景比较局限。
可以移步至我的个人博客顶顶我的博客:锡城小凯的博客
我会把地图放在里面,也会逐步更新到github
[1].https://blog.csdn.net/weixin_41754912/article/details/82353012#2-v-rep%E9%85%8D%E7%BD%AE
[2].https://www.cnblogs.com/21207-iHome/p/7115487.html
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。