chono challenge


  • Home

  • Archives

Ultra96_v2笔记

Posted on 2020-03-06

开机联网

准备工作

1.Ultra96_v2电源(与PYNQ -Z2不同,U96的板子必须得用电源供电,而且买的开发板是不带电源的。其电源接口为4.8mm而不是5.5m这里我们买了一个12v 2A d的电源和一个5.5x2.1母转4.8x1.7的转接线)

2.MicroSD卡,官网下载镜像文件并用Win32Diskmager写入。(板子包装带有读卡器和SD卡)

3.usb线

进入系统

按照官方教程进入之后开机之后,可以直接访问192.168.3.1进入jupyter notebook.

1.通过jupyter notebook下common/wifi.ipynb文件可进行联网

2.通过jupyter notebook 右上角新建terminal 可直接进入操作系统terminal

这里也可以通过串口访问terminal,官方给出putty教程,这里介绍使用x-shell访问

​ (1)在插入USB的情况下,访问计算机设备管理器查看端口号

​ (2)打开x-shell新建连接,给新的连接任意命名,并选择SERIAL协议(默认为SSH)

​ (3)在SERIAL下,修改端口号为(1)中端口号,波特率为115200,最后点击连接,即可进入。

进入之后,会看到提示为Ubuntu18

第二种访问方式

上面提到可直接通过USB 登入192.168.3.1访问jupyter并联网。这里也可以通过串口访问系统后。利用linux命令联网(自行百度),用ifconfig命令查询U96的IP。然后通过该IP访问Jupyter(要求计算机和U96在同一局域网)

访问系统文件

开发板开启后,会开启Samba文件共享服务。这时只需在windows资源管理器中访问以下链接即可(注意在是在USB线连接的情况下),打开后即可和计算机交换文件。

1
\\192.168.3.1\xilinx

我的系统是win10,发现不能直接访问,访问提示不存在。因此,应该是计算机的文件共享服务未启用。这时按照这个网站操作即可https://jingyan.baidu.com/article/2a138328d7b94c074a134f27.html
这里将简述操作步骤
(1)win+R 打开运行搜索框
(2)输入 gpedit.msc 后,确定
(3)在本地组策略编辑器对话框中,依次单击“计算机配置”“管理模板”“网络”。
(4)单击“lanman工作站”。
(5)双击“启用不安全的来宾登录”,单击“已启用”,单击“确定”即可。
这时发现就可以访问了

安装ROS

因为U96采用的是Ubuntu18,因此这里注意ROS kinetic版本是不支持直接安装的。所以这里选择支持Ubuntu18的ROS Melodic版本。刚开始直接使用官方给出的源,一直显示IP not found的问题,于是按照这个网站的源进行操作

https://www.antongvozdev.com/portfolio/ros-installation/

首先terminal(用jupyter 或者x-shell打开都可)输入

1
export ROS_OS_OVERRIDE=ubuntu:bionic

接着输入,和官方给出的源相比用 bionic 替换了$(lsb_release -sc)

1
sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu bionic main" > /etc/apt/sources.list.d/ros-latest.list'

然后按照官方教程添加密钥,

1
sudo apt-key adv --keyserver 'hkp://keyserver.ubuntu.com:80' --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654

更新源

1
sudo apt update

安装(注意这里是ROS Melodic),比较耗时,我用了一个多小时

1
sudo apt install ros-melodic-desktop-full

初始化rosdep(此步骤可能会遇到问题参考https://www.jianshu.com/p/bdbfbac69114 )

1
2
sudo rosdep init
rosdep update

设置环境变量(加入bashrc文件,使得所有的terminal都生效)

1
2
echo "source /opt/ros/melodic/setup.bash" >> ~/.bashrc
source ~/.bashrc

安装rosinsatall

1
sudo apt install python-rosinstall python-rosinstall-generator python-wstool build-essential

安装完成

注:我在初始化rosdep步骤,产生的问题为

1
2
3
4
sudo rosdep init
ERROR: cannot download default sources list from:
https://raw.githubusercontent.com/ros/rosdistro/master/rosdep/sources.list.d/20-default.list
Website may be down.

解决方法为打开该网站,其为文本内容

1
2
3
4
5
6
7
8
9
10
# os-specific listings first
yaml https://raw.githubusercontent.com/ros/rosdistro/master/rosdep/osx-homebrew.yaml osx

# generic
yaml https://raw.githubusercontent.com/ros/rosdistro/master/rosdep/base.yaml
yaml https://raw.githubusercontent.com/ros/rosdistro/master/rosdep/python.yaml
yaml https://raw.githubusercontent.com/ros/rosdistro/master/rosdep/ruby.yaml
gbpdistro https://raw.githubusercontent.com/ros/rosdistro/master/releases/fuerte.yaml fuerte

# newer distributions (Groovy, Hydro, ...) must not be listed anymore, they are being fetched from the rosdistro index.yaml instead

将该文本复制到 /etc/ros/rosdep/sources.list.d/20-default.list文本文件中,若rosdep update报错,执行

1
2
sudo apt-get update
sudo apt-get install python-rosdep

还不清楚为什么只安装python-rosdep,后续会测试一下能不能编译c++包

ROS使用常见问题

安装后,按照ros wiki的教程创建工作空间和功能报即可。过程中遇到的一些问题在这里总结

1.创建功能包后,如何把win10中编辑的源文件(.py/.cpp)拷入功能包中?

答:可通过直接访问windows 资源管理器按照上面提出的方法,访问

1
\\192.168.3.1\xilinx

即可,但是会发现文件夹为只读,不能直接拷入,使用以下命令修改文件夹权限

1
chmod -R 777 catkin_ws #改变该工作空间的权限

2.运行功能包时出现:/usr/bin/env: ‘python\r’: No such file or directory问题?

这是由于window和linux的编码方式引起的,这里采用一个dos2unix包的小工具修改文件编码即可。

参考: https://blog.csdn.net/NiYintang/article/details/86124338

1
2
sudo apt-get install dos2unix
dos2unix <filename

桌面环境安装

在jupyter的terminal中打开时,发现有vncserver时提示如下错误

1
vncserver: The HOME environment variable is not set.

于是用x-shell连接,发现能够使用了

http://www.scutmath.com/ubuntu_vnc.html

按照这个教程,安装到最后,桌面访问一直是灰色的,搞不清什么原因

试了gnome 和xfce,改了好多次xstartup文件(可通过win10资源管理器直接打开.vnc文件夹修改),一直未能成功,后面有时间再接着研究

Ultra96_V2(2)

Posted on 2020-03-06

简单开发

参考Ultra96 _v1的教程实现

教程1

vivado 下载

xilinx提供了vivado-webpack版本,该版本为免费版本,支持的产品型号虽然有限制。但是支持U96,为了省去后面各种license问题,这里下载wepack版本。

(1)注册xilinx账号,登陆下载页面https://www.xilinx.com/support/download.html

(2)选择对应系统版本的统一下载器,不到100M(下载后再选择下载的Xilinx产品),这里用的是windows.选择的是Xilinx Unified Installer 2019.2: Windows Self Extracting Web Installer

(3)下载后打开,然后登录Xilinx账户,选择vivado然后 Vivado HL WebPack版本下载。然后可以选择相应的器件型号。安装即可(U96选择如下即可,需要空间约40G,下载内容12.88G,用时较长),该下载器下载后会自动安装完成。

U96开发板定义文件下载

(1)进入Avnet github,选择其bdf(Board Definition Files)文件库下载https://github.com/Avnet/bdf

(2) 解压后将其中的Ultra96v2文件夹复制到board_files文件夹

Untitled

Posted on 2020-03-04

前言

前言提纲

交代研究背景

说明研究内容重要性

指出目前研究的不足(重要)

提出研究的问题

简要说明解决方法

说明为什么用上述方法(重要,需要明确表现出来)

给出文章结构

前言内容

(1)介绍领域大背景,逐渐聚焦到研究内容

让本领域研究人员了解论文工作中的点,并显示出这个点在这个领域的重要性

(2)介绍研究内容的研究进展和前沿

(3)说明论文研究的问题

(4)

(5)说明文章的创新的与贡献(重要)

(6)简要说明文章结构

Untitled

Posted on 2020-03-03

title:Ultra96_v2笔记

开机联网

准备工作

1.Ultra96_v2电源(与PYNQ -Z2不同,U96的板子必须得用电源供电,而且买的开发板是不带电源的。其电源接口为4.8mm而不是5.5m这里我们买了一个12v 2A d的电源和一个5.5x2.1母转4.8x1.7的转接线)

2.MicroSD卡,官网下载镜像文件并用Win32Diskmager写入。(板子包装带有读卡器和SD卡)

3.usb线

进入系统

按照官方教程进入之后开机之后,可以直接访问192.168.3.1进入jupyter notebook.

1.通过jupyter notebook下common/wifi.ipynb文件可进行联网

2.通过jupyter notebook 右上角新建terminal 可直接进入操作系统terminal

这里也可以通过串口访问terminal,官方给出putty教程,这里介绍使用x-shell访问

​ (1)在插入USB的情况下,访问计算机设备管理器查看端口号

​ (2)打开x-shell新建连接,给新的连接任意命名,并选择SERIAL协议(默认为SSH)

​ (3)在SERIAL下,修改端口号为(1)中端口号,波特率为115200,最后点击连接,即可进入。

进入之后,会看到提示为Ubuntu18

第二种访问方式

上面提到可直接通过USB 登入192.168.3.1访问jupyter并联网。这里也可以通过串口访问系统后。利用linux命令联网(百度),用ifconfig命令查询U96的IP。然后通过该IP访问Jupyter(要求计算机和U96在同一局域网)

访问系统文件

开发板开启后,会开启Samba文件共享服务。这时只需在windows资源管理器中访问以下链接即可(注意在是在USB线连接的情况下),打开后即可和计算机交换文件。

1
\\192.168.3.1\xilinx

我的系统是win10,发现不能直接访问,访问提示不存在。因此,应该是计算机的文件共享服务未启用。这时按照这个网站操作即可https://jingyan.baidu.com/article/2a138328d7b94c074a134f27.html
这里将简述操作步骤
(1)win+R 打开运行搜索框
(2)输入 gpedit.msc 后,确定
(3)在本地组策略编辑器对话框中,依次单击“计算机配置”“管理模板”“网络”。
(4)单击“lanman工作站”。
(5)双击“启用不安全的来宾登录”,单击“已启用”,单击“确定”即可。
这时发现就可以访问了

安装ROS

因为U96采用的是Ubuntu18,因此这里注意ROS kinetic版本是不支持直接安装的。所以这里选择支持Ubuntu18的ROS Melodic版本。刚开始直接使用官方给出的源,一直显示IP not found的问题,于是按照这个网站的源进行操作

https://www.antongvozdev.com/portfolio/ros-installation/

首先terminal(用jupyter 或者x-shell打开都可)输入

1
export ROS_OS_OVERRIDE=ubuntu:bionic

接着输入,和官方给出的源相比用 bionic 替换了$(lsb_release -sc)

1
sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu bionic main" > /etc/apt/sources.list.d/ros-latest.list'

然后按照官方教程添加密钥,

1
sudo apt-key adv --keyserver 'hkp://keyserver.ubuntu.com:80' --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654

更新源

1
sudo apt update

安装(注意这里是ROS Melodic),比较耗时,我用了一个多小时

1
sudo apt install ros-melodic-desktop-full

初始化rosdep(此步骤可能会遇到问题参考https://www.jianshu.com/p/bdbfbac69114 )

1
2
sudo rosdep init
rosdep update

设置环境变量(加入bashrc文件,使得所有的terminal都生效)

1
2
echo "source /opt/ros/melodic/setup.bash" >> ~/.bashrc
source ~/.bashrc

安装rosinsatall

1
sudo apt install python-rosinstall python-rosinstall-generator python-wstool build-essential

安装完成

注:我在初始化rosdep步骤,产生的问题为

1
2
3
4
sudo rosdep init
ERROR: cannot download default sources list from:
https://raw.githubusercontent.com/ros/rosdistro/master/rosdep/sources.list.d/20-default.list
Website may be down.

解决方法为打开该网站,其为文本内容

1
2
3
4
5
6
7
8
9
10
# os-specific listings first
yaml https://raw.githubusercontent.com/ros/rosdistro/master/rosdep/osx-homebrew.yaml osx

# generic
yaml https://raw.githubusercontent.com/ros/rosdistro/master/rosdep/base.yaml
yaml https://raw.githubusercontent.com/ros/rosdistro/master/rosdep/python.yaml
yaml https://raw.githubusercontent.com/ros/rosdistro/master/rosdep/ruby.yaml
gbpdistro https://raw.githubusercontent.com/ros/rosdistro/master/releases/fuerte.yaml fuerte

# newer distributions (Groovy, Hydro, ...) must not be listed anymore, they are being fetched from the rosdistro index.yaml instead

将该文本复制到 /etc/ros/rosdep/sources.list.d/20-default.list文本文件中,若rosdep update报错,执行

1
2
sudo apt-get update
sudo apt-get install python-rosdep

还不清楚为什么只安装python-rosdep,后续会测试一下能不能编译c++包

ROS使用常见问题

安装后,按照ros wiki的教程创建工作空间和功能报即可。过程中遇到的一些问题在这里总结

1.创建功能包后,如何把win10中编辑的源文件(.py/.cpp)拷入功能包中?

答:可通过直接访问windows 资源管理器按照上面提出的方法,访问

1
\\192.168.3.1\xilinx

即可,但是会发现文件夹为只读,不能直接拷入,使用以下命令修改文件夹权限

1
chmod -R 777 catkin_ws #改变该工作空间的权限

2.运行功能包时出现:/usr/bin/env: ‘python\r’: No such file or directory问题?

这是由于window和linux的编码方式引起的,这里采用一个dos2unix包的小工具修改文件编码即可。

参考: https://blog.csdn.net/NiYintang/article/details/86124338

1
2
sudo apt-get install dos2unix
dos2unix <filename

桌面环境安装

在jupyter的terminal中打开时,发现有vncserver时提示如下错误

1
vncserver: The HOME environment variable is not set.

于是用x-shell连接,发现能够使用了

http://www.scutmath.com/ubuntu_vnc.html

按照这个教程,安装到最后,桌面访问一直是灰色的,搞不清什么原因

试了gnome 和xfce,改了好多次xstartup文件(可通过win10资源管理器直接打开.vnc文件夹修改),一直未能成功,后面有时间再接着研究

Computer Vision in U96

cv2.imshow函数不能直接用于jupyter

Untitled

Posted on 2020-01-29

Title: 算法

问题

在写程序时,经常会遇到两个问题,一个是在同一个平台上不同的算法有不同的执行效率,另一个是对于同一个算法,在不同平台上的执行效率。第一个问题涉及到的是数据结构与算法相关的问题,而第二个问题涉及到的是硬件层面的关于处理器架构的问题。当然,两个问题并不是孤立的,对于某一特定的架构,可能会有最适合其的算法,操作系统和编译器。这是一个很庞大的问题。需要找到一个出发点。这里先从算法这个点去入手。

FPGA文档参考

Posted on 2020-01-12

FPGA 架构

FPGA基础结构由一下四部分构成
.Look Up Table(LUT) :执行逻辑操作
.Flip-Flop(FF):存储LUT计算结果
.Wires:连接线
.Input/Output(I/O)pads:输入输出接口

如下所示:

由这些基础的可配置逻辑单元(Configurable Logic Block,CLB),可以实现任何算法。但是从实现效率,资源消耗和可实现的时钟频率上来说,会有一些限制。
因此,如今先进的FPGA框架又加入了一些新的计算和存储结构,分别是:
• Embedded memories for distributed data storage
• Phase-locked loops (PLLs) for driving the FPGA fabric at different clock rates
• High-speed serial transceivers
• Off-chip memory controllers
• Multiply-accumulate blocks

下面分别讨论以上集中结构

LUT

查找表,

Untitled

Posted on 2020-01-07

–

title:Opencv学习笔记

##基本数据类型
Mat:表示任意维度的稠密数组

#立体匹配
Opencv中提供了两种立体匹配算法,块匹配算法BM和班全局块匹配SGBM

cvFindStereoCorrespondenceBM

1
2
3
4
5
void cvFindStereoCorrespondenceBM(
const CvArr* left,
const CvArr* right,
CvArr* disparity,
CvStereoBMState* state );

深度学习入门

Posted on 2019-12-31

##

逻辑电路构造的与非门输入为二进制,而感知机构造的与非门输入为10进制,理论上可以可以用python实现一个“虚拟”的计算机。

利用gazebo中的立体相机进行定位

Posted on 2019-12-13

预备知识

上一篇文章介绍了如何建立双目相机模型及其参数。接下来利用这个双目相机进行物体的定位。在使用立体相机进行定位时,我们需要以下几个参数:
1.相机焦距 :flength 单位:pixel(像素)
2.两个相机的距离即基线:baseline 单位:m(米)
3.图像的大小(分辨率):height x width 单位:pixel(像素)
—理想相机中点坐标分别为cx = wigth/2,cy = height/2
4.我们定位的点在左右目中的图像定位的点是(xl,yl),(xr,yr)(单位:pixel(像素))

其中,前3个参数在相机固定时就已经是定值(当然对于有畸变的相机,需要相机实际的焦距和中心点cx,xy)。第四个参数需要我们用图像处理的方法得到(后面会涉及)。由以上参数我们就可以得到以下计算相机的深度depth和x,y的位置(相对于左目):

1
2
3
4
5
#立体位置计算
disparity = abs(xl- xr)
depth = (flength * baseline)/(disparity)
x = ((xl - cx) * baseline)/(disparity)
y = (( yl - cy) * baseline)/(disparity)

这里只是给出结果,具体的原理分析需要作图分析,后面再写篇文章,网上也有很多相关的介绍和教材可以参考。

定位算法

这里来用一个测试程序来说明结果的正确性,主要由以下步骤。
1.rosrun gazebo_ros gazebo 打开gazeo
2.将上篇文章提到的立体相机模型手动放到原点位置,然后在镜头前不远处放入一个小球,这里我用的模型库里的RoboCup_SPL_Ball,然后打开rqt_image_view查看是否有小球,并查看是否在左右相机中小球视角发生变化。
3.订阅相机发布的图像,处理得到左右目中小球球心的位置,计算(x,y,depth)
4.与gazebo中小球的位置对比(一个格子1m可以直接对比)。
以下是python实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#利用获取的双目图像进行定位
import rospy
import cv2
import message_filters
from cv_bridge import CvBridge, CvBridgeError
from sensor_msgs.msg import Image
import math #计算正切

bridge = CvBridge()
hfov = 1.3962634
image_width = 800
flength = (image_width/2) / ( math.tan(hfov/2) )
base_line = 0.2
cx = 400
cy = 400
def callback(left_ros_image,right_ros_image):
global flength
global cx
global cy

left_cv_image = bridge.imgmsg_to_cv2(left_ros_image)
right_cv_image = bridge.imgmsg_to_cv2(right_ros_image)
#图像处理获取参考点图像坐标
grayl = cv2.cvtColor(left_cv_image, cv2.COLOR_BGR2GRAY) #灰度化
grayr = cv2.cvtColor(right_cv_image, cv2.COLOR_BGR2GRAY)
ret1l,andMaskBil = cv2.threshold(grayl, 100, 255, cv2.THRESH_BINARY_INV); #进行阈值操作,这里针对其颜色做了一个反转_INV
ret1r,andMaskBir = cv2.threshold(grayr, 100, 255, cv2.THRESH_BINARY_INV);

ret2l,contoursl, hierarchyl = cv2.findContours(andMaskBil.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)#轮廓查找注意此算法当背景为白色物体为黑色时,可能使得最后的轮廓只有边框
ret2r,contoursr, hierarchyr = cv2.findContours(andMaskBir.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

cntl = contoursl[0] #取该条轮廓,默认图像中只有一个轮廓,所以视野中只放一个小球
Ml = cv2.moments(cntl)#计算轮廓的矩
cxl_f=((Ml['m10']/Ml['m00'])) #浮点数表示的质心横坐标
cyl_f=((Ml['m01']/Ml['m00'])) #浮点数表示的质心纵坐标



cntr = contoursr[0] #取该条轮廓
Mr = cv2.moments(cntr)#计算轮廓的矩
cxr_f=((Mr['m10']/Mr['m00'])) #浮点数表示的质心横坐标
cyr_f=((Mr['m01']/Mr['m00'])) #浮点数表示的质心纵坐标

disparity = abs(cxl_f - cxr_f)
depth = (flength * base_line)/(disparity)
x = ((cxl_f - cx) * base_line)/(disparity)
y = (( cyl_f - cy) * base_line)/(disparity)
print(x)
print(y)
print(depth)
#图像显示
cv2.imshow('left_image',left_cv_image)
cv2.imshow('andMaskBil',andMaskBil)
key =cv2.waitKey(30)


if __name__ == '__main__':
rospy.init_node('gazebo_image_sub', anonymous=True)

left_ros_image = message_filters.Subscriber("/multisense_sl/camera/left/image_raw", Image)
right_ros_image =message_filters.Subscriber("/multisense_sl/camera/right/image_raw", Image)
ts = message_filters.TimeSynchronizer([left_ros_image , right_ros_image], 10)
ts.registerCallback(callback)
# spin() simply keeps python from exiting until this node is stopped
rospy.spin()

gazebo中加入一个双目相机及相机参数设置

Posted on 2019-12-11

kinect

为了在gazebo中观察并利用利用视觉进行小球的定位并与ros通信,我们需要一个深度相机,这时可以直接使用kinect并加入插件与ros通信,gazebo官方也为我们提供了这个方法
http://gazebosim.org/tutorials/?tut=ros_depth_camera
直接将Kinect的模型文件下载在

1
2
3
4
5
<sensor>
....
</camera>
在此处添加插件代码即可
</sendor>

但有时,我们需要得到左右目两张图像,这是,我们就需要一个双目相机模型。

##双目相机
方法类似,我们可以继续使用kinect的外观,使用一个Muticamera插件,
http://gazebosim.org/tutorials?tut=ros_gzplugins
这时只需要将上述文件的sensor部分替换为官方给出的sensor部分的代码即可。这时在rqt_image_view中可以看到left和right两张图像

注意:以上两种修改sdf文件的方法不要忘记修改模型文件夹名字,sdf文件中的model名字,以及config文件中的model名

显示

首选,用rosrun gazebo_ros gazebo命令打开gazebo之后,在新的终端输入rostopic list,我们可以看到左右目的话题都在发布,主要是以下两个话题,

1
2
/multisense_sl/camera/left/image_raw
/multisense_sl/camera/left/image_raw

我们的目的是订阅这两个话题并显示,我们先尝试订阅一个话题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#订阅gazebo中双目相机左目的图像并显示
import rospy
import cv2
import message_filters
from cv_bridge import CvBridge, CvBridgeError
from sensor_msgs.msg import Image
#ros传感器和opencv中的图像类型转换
bridge = CvBridge()
#回调函数
def callback(left_ros_image):
left_cv_image = bridge.imgmsg_to_cv2(left_ros_image)
cv2.imshow('left_image',left_cv_image)
key =cv2.waitKey(1)

if __name__ == '__main__':
#初始化节点
rospy.init_node('gazebo_image_sub', anonymous=True)
#订阅左目图像
left_ros_image = rospy.Subscriber("/multisense_sl/camera/left/image_raw", Image,callback)
rospy.spin()

注意,这前两行别忘了复制,不然可能会出现编码错误

ok,接下来我们显示双目图像,我们这里用到ros的一个message_filter的包,里面有一个Time Synchronizer,可以将接收到的信息进行同步。
https://wiki.ros.org/message_filters#Time_Synchronizer

191217补充:采用这种方式发现程序经常运行一会儿就会卡住,后来发现是cv2.imshow()的问题,将其注释掉,就不会卡住了。具体原因还没找到。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#订阅gazebo中双目相机的图像并显示
import rospy
import cv2
import message_filters
from cv_bridge import CvBridge, CvBridgeError
from sensor_msgs.msg import Image

bridge = CvBridge()


def callback(left_ros_image,right_ros_image):
left_cv_image = bridge.imgmsg_to_cv2(left_ros_image)
right_cv_image = bridge.imgmsg_to_cv2(right_ros_image)
cv2.imshow('left_image',left_cv_image)
cv2.imshow('right_image',right_cv_image)
key =cv2.waitKey(1)


if __name__ == '__main__':
rospy.init_node('gazebo_image_sub', anonymous=True)

left_ros_image = message_filters.Subscriber("/multisense_sl/camera/left/image_raw", Image)
right_ros_image =message_filters.Subscriber("/multisense_sl/camera/right/image_raw", Image)
ts = message_filters.TimeSynchronizer([left_ros_image , right_ros_image], 10)
ts.registerCallback(callback)
# spin() simply keeps python from exiting until this node is stopped
rospy.spin()

插件参数

ok,现在我们想试一下这个立体相机能不能工作,我们需要知道我们到底对这个相机做了什么。介绍这部分之前,可以先看看有关相机镜头畸变和矫正相关的内容。这里在代码中对其进行注释。以下是整个立体相机的module.sdf文件。

1
2
3
4
5
<?xml version="1.0" ?>
<sdf version="1.5">
<model name="Stere_camera">
<static>True</static>
<pose>0 0 0.2 0 0 3.14</pose>

开始module标签定义了模型的名字,pose标签指定初始位置,这里我理解的是相对于gazebo中的世界坐标系。static可省略,这里让其为True是想让相机不借助其他模型悬浮在空中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<link name="link">
<inertial>
<mass>0.1</mass>
</inertial>
<collision name="collision">
<geometry>
<box>
<size>0.073000 0.276000 0.072000</size>
</box>
</geometry>
</collision>
<visual name="visual">
<geometry>
<mesh>
<uri>model://kinect/meshes/kinect.dae</uri>
</mesh>
</geometry>
</visual>

以上主要是三个标签,inertial中定义了模型质量(但由于我们将static设置为True这里相机将不受重力影响)。collision定义其物理属性,指的是在和其他物体碰撞时,以geometry中的属性进行碰撞。而visual标签中的geometry是指视觉效果。(我目前的理解是这样,如果visual中定以为球,而collision中定义为正方体,给这个物体一个力他会滑动,而不是滚动。因为collison中定义的是物理形状,而visual只是视觉形状)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<sensor type="multicamera" name="stereo_camera">
<update_rate>30.0</update_rate>
<camera name="left">
<horizontal_fov>1.3962634</horizontal_fov>
<image>
<width>800</width>
<height>800</height>
<format>R8G8B8</format>
</image>
<clip>
<near>0.02</near>
<far>300</far>
</clip>
<noise>
<type>gaussian</type>
<mean>0.0</mean>
<stddev>0.007</stddev>
</noise>
</camera>
<camera name="right">
<pose>0 -0.07 0 0 0 0</pose>
<horizontal_fov>1.3962634</horizontal_fov>
<image>
<width>800</width>
<height>800</height>
<format>R8G8B8</format>
</image>
<clip>
<near>0.02</near>
<far>300</far>
</clip>
<noise>
<type>gaussian</type>
<mean>0.0</mean>
<stddev>0.007</stddev>
</noise>
</camera>

以上是两个传感器,我们可以看到是两个相同的传感器,其定义的属性从标签上就能看出来,这里重点是三个标签,clip中定义了相机能看到的最远和最近位置(现实中因为你焦点的原因,相机看物体模糊但也不至于看不到,所以搞不太懂这个标签的物理意义)。nosie是像素上的噪声,结合实际相机,很容易理解。最后重点说一下pose我们发现left相机是没有pose标签的,默认为0 0 0 0 -0 0,而right相机有个-0.07,负号说明其在右边,0.07就是指的基线的距离。(在这里这个pose还不知道具体是什么,是相机坐标系的原点,还是图像坐标系的远点,在深度上相差一个焦距的距离。关于这两个坐标系,见
https://blog.csdn.net/chentravelling/article/details/53558096) 这个是我们进行立体计算时需要用到的。这时我们发现对于一个镜头来说还需要一个很重要的参数,那就是焦距。但这里并没有给出,实际上我们可以根据水平视场horizontal_fov来计算出来的,参考以下两个介绍:
http://playerstage.sourceforge.net/wiki/GazeboProblemResolutionGuide
https://answers.ros.org/question/12658/how-to-change-gazebo-gui-focal-lengthfov/
即可以通过以下公式得到焦距:
flength = (width/2)/tan(hfov/2)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
      <plugin name="stereo_camera_controller" filename="libgazebo_ros_multicamera.so">
<alwaysOn>true</alwaysOn>
<updateRate>0.0</updateRate>
<cameraName>multisense_sl/camera</cameraName>
<imageTopicName>image_raw</imageTopicName>
<cameraInfoTopicName>camera_info</cameraInfoTopicName>
<frameName>left_camera_optical_frame</frameName>
<!--<rightFrameName>right_camera_optical_frame</rightFrameName>-->
<hackBaseline>0.07</hackBaseline>
<distortionK1>0.0</distortionK1>
<distortionK2>0.0</distortionK2>
<distortionK3>0.0</distortionK3>
<distortionT1>0.0</distortionT1>
<distortionT2>0.0</distortionT2>
</plugin>
</sensor>
</link>
</model>
</sdf>

以上是传感器插件,我们发现和单目相机的插件很像,主要说下最后几个参数,如果做过单目相机矫正就很容易理解(K1 K2 T1 T2 K3)是相机的畸变系数,这里使其为0,即认为相机没有畸变,理想化了。hackBaseline这里现在也没太搞懂是啥,需要再研究一下。

123

John Doe

29 posts
© 2020 John Doe
Powered by Hexo
|
Theme — NexT.Muse v5.1.4