Jetson Xavier NX 试玩 (三)

发布时间 2023-06-03 17:49:25作者: Baiyug

Jetson Xavier NX 试玩 (三)

玩一下 ZED MINI

0 前言

ZED Mini是一款优秀的双目摄像头,功能丰富。

除了深度视觉功能,它还内置了加速度计、陀螺仪、磁力计、气压计等传感器。

众所周知,双目摄像头可应用于空间定位,且精度很高,做过是室内定位应用的同学可能或多或少玩过英特尔家的T265双目摄像头,它内置 VPU ,可以自己运行 slam 算法,对于主机的硬件要求不高。但是,官方在2022年就停止了这个项目,
https://discuss.ardupilot.org/t/intel-stop-production-of-t265-feb-2022/77311

也就是说,T265尚存的一些bug官方不会修复了(maybe),该项目的一些衍生应用都会受到一定的影响。

ZED Mini作为一款双目相机,定位功能肯定是有的,那么效果如何呢?

正巧,我手里有一款 ZED Mini,那就来玩一玩吧。

1 查看GPU

ZED Mini 的使用需要一定的GPU算力支持

那么我们的Jetson Xavier NX支不支持呢,本着严谨的态度,我们查看一下。

官方提供了查看方法,https://forums.developer.nvidia.com/t/what-compute-capability-of-jetson-xavier-nx-gpu-is/146241

做一下,如下

jetson@ubuntu:/usr/local/cuda-10.2/samples/1_Utilities/deviceQuery$ ls
deviceQuery.cpp  Makefile  NsightEclipse.xml  readme.txt
jetson@ubuntu:/usr/local/cuda-10.2/samples/1_Utilities/deviceQuery$ make 
/usr/local/cuda-10.2/bin/nvcc -ccbin g++ -I../../common/inc  -m64    -gencode arch=compute_30,code=sm_30 -gencode arch=compute_32,code=sm_32 -gencode arch=compute_53,code=sm_53 -gencode arch=compute_61,code=sm_61 -gencode arch=compute_62,code=sm_62 -gencode arch=compute_70,code=sm_70 -gencode arch=compute_72,code=sm_72 -gencode arch=compute_75,code=sm_75 -gencode arch=compute_75,code=compute_75 -o deviceQuery.o -c deviceQuery.cpp
Assembler messages:
Fatal error: can't create deviceQuery.o: Permission denied
Makefile:310: recipe for target 'deviceQuery.o' failed
make: *** [deviceQuery.o] Error 1
jetson@ubuntu:/usr/local/cuda-10.2/samples/1_Utilities/deviceQuery$ sudo make
/usr/local/cuda-10.2/bin/nvcc -ccbin g++ -I../../common/inc  -m64    -gencode arch=compute_30,code=sm_30 -gencode arch=compute_32,code=sm_32 -gencode arch=compute_53,code=sm_53 -gencode arch=compute_61,code=sm_61 -gencode arch=compute_62,code=sm_62 -gencode arch=compute_70,code=sm_70 -gencode arch=compute_72,code=sm_72 -gencode arch=compute_75,code=sm_75 -gencode arch=compute_75,code=compute_75 -o deviceQuery.o -c deviceQuery.cpp
/usr/local/cuda-10.2/bin/nvcc -ccbin g++   -m64      -gencode arch=compute_30,code=sm_30 -gencode arch=compute_32,code=sm_32 -gencode arch=compute_53,code=sm_53 -gencode arch=compute_61,code=sm_61 -gencode arch=compute_62,code=sm_62 -gencode arch=compute_70,code=sm_70 -gencode arch=compute_72,code=sm_72 -gencode arch=compute_75,code=sm_75 -gencode arch=compute_75,code=compute_75 -o deviceQuery deviceQuery.o 
mkdir -p ../../bin/aarch64/linux/release
cp deviceQuery ../../bin/aarch64/linux/release
jetson@ubuntu:/usr/local/cuda-10.2/samples/1_Utilities/deviceQuery$ ls
deviceQuery      deviceQuery.o  NsightEclipse.xml
deviceQuery.cpp  Makefile       readme.txt
jetson@ubuntu:/usr/local/cuda-10.2/samples/1_Utilities/deviceQuery$ ./deviceQuery 
./deviceQuery Starting...

 CUDA Device Query (Runtime API) version (CUDART static linking)

Detected 1 CUDA Capable device(s)

Device 0: "Xavier"
  CUDA Driver Version / Runtime Version          10.2 / 10.2
  CUDA Capability Major/Minor version number:    7.2
  Total amount of global memory:                 7765 MBytes (8142626816 bytes)
  ( 6) Multiprocessors, ( 64) CUDA Cores/MP:     384 CUDA Cores
  GPU Max Clock rate:                            1109 MHz (1.11 GHz)
  Memory Clock rate:                             1109 Mhz
  Memory Bus Width:                              256-bit
  L2 Cache Size:                                 524288 bytes
  Maximum Texture Dimension Size (x,y,z)         1D=(131072), 2D=(131072, 65536), 3D=(16384, 16384, 16384)
  Maximum Layered 1D Texture Size, (num) layers  1D=(32768), 2048 layers
  Maximum Layered 2D Texture Size, (num) layers  2D=(32768, 32768), 2048 layers
  Total amount of constant memory:               65536 bytes
  Total amount of shared memory per block:       49152 bytes
  Total number of registers available per block: 65536
  Warp size:                                     32
  Maximum number of threads per multiprocessor:  2048
  Maximum number of threads per block:           1024
  Max dimension size of a thread block (x,y,z): (1024, 1024, 64)
  Max dimension size of a grid size    (x,y,z): (2147483647, 65535, 65535)
  Maximum memory pitch:                          2147483647 bytes
  Texture alignment:                             512 bytes
  Concurrent copy and kernel execution:          Yes with 1 copy engine(s)
  Run time limit on kernels:                     No
  Integrated GPU sharing Host Memory:            Yes
  Support host page-locked memory mapping:       Yes
  Alignment requirement for Surfaces:            Yes
  Device has ECC support:                        Disabled
  Device supports Unified Addressing (UVA):      Yes
  Device supports Compute Preemption:            Yes
  Supports Cooperative Kernel Launch:            Yes
  Supports MultiDevice Co-op Kernel Launch:      Yes
  Device PCI Domain ID / Bus ID / location ID:   0 / 0 / 0
  Compute Mode:
     < Default (multiple host threads can use ::cudaSetDevice() with device simultaneously) >

deviceQuery, CUDA Driver = CUDART, CUDA Driver Version = 10.2, CUDA Runtime Version = 10.2, NumDevs = 1
Result = PASS

看到我们的 CUDA Capability Major/Minor version number 是7.2,应该是能够驾驭ZED Mini的SDK,不过它的虚拟现实功能必须在Windows系统上,并且对显卡有了更高的要求,在jetson上就无能为力了。

2 安装SDK

https://www.stereolabs.com/docs/installation/jetson/

官网找到对应LT4版本的ZED SDK ,是一个xxx.run文件,然后给权限,执行,就可以下载相关SDK了。

我在下载过程中遇到一些网络问题,下载过程非常的慢,甚至有时某些模块下载失败,明明是开了代理的。

同时我发现,并不是每一条网络请求都走proxy,这让我感到不解,只能暂时作罢。

也有可能是我的局域网环境有些差的缘故,没啥方法,只能多试几次。

突然发现我对于代理的理解还不够,只是设置系统代理应该是不够的,某些软件访问网址是不走系统代理的。

找到了个不错的设置代理的脚本

https://github.com/nityanandagohain/proxy_configuration

该脚本设置了 apt 、env 、bashrc

(设置完后,下载这个SDK的速度就快多了)

3 运行第一个程序

就以C++为例

https://www.stereolabs.com/docs/app-development/cpp/linux/

cd /home/jetson/baiyug_ws/ZED_Mini/zed-examples/tutorials/tutorial 1 - hello ZED/cpp
mkdir build && cd build
cmake ..
make
./ZED_Tutorial_1 

还有很多例程,不一一演示了。

4 ZED ROS wrapper

官方也提供了关于ros的使用程序
https://www.stereolabs.com/docs/ros/

4.1 ros install

http://wiki.ros.org/melodic/Installation/Ubuntu

这一步没什么难的,唯一需要解决的应该外网访问问题。

4.2 克隆zed-ros-wrapper

选个文件夹作为zed-ros的工作目录,然后clone就行

mkdir -p zedros_ws/src
cd zedros_ws/src
git clone https://github.com/stereolabs/zed-ros-wrapper.git

然后就是catkin_make

留意一下,截至20230425,zed-ros-wrapper这个工程只支持ZED SDK 4版本,更早的版本编译时会报错。
(可惜官方并没有说清楚,害得我重装了一遍SDK?)

然后就编译ros工作空间即可

catkin_make

然后就是要添加一下环境变量

source ~/baiyug_ws/zedros_ws/devel/setup.bash

如果不想每开一次终端就source一遍,就把这个命令添加到~/.bashrc里,可以直接复制黏贴到该文件,也可以直接用以下命令

echo "source ~/baiyug_ws/zedros_ws/devel/setup.bash" >> ~/.bashrc

然后运行一下

source ~/.bashrc

使用以下命令查看环境变量是否添加成功

echo $ROS_PACKAGE_PATH

要启动zed-ros-wrapper的各个节点可以使用launch文件,zed mini用这个

roslaunch zed_wrapper zedm.launch

这样可能不太直观,可以用rviz看一下

4.3 Displaying ZED data

cd ~/zedros_ws/src
git clone https://github.com/stereolabs/zed-ros-examples.git

cd ..
catkin_make
roslaunch zed_display_rviz display_zedm.launch

综上,我们现在可以得到ZED mini提供的空间位置信息,深度视觉信息等等。这些信息在机器人导航中有着重要的应用。以无人机为例,这些信息能够使得室内无人机的控制精度达到厘米级。(当然,这是商用级产品的效果)

5 我必须立刻控制位置!

利用ros,我们可以轻易地获得zed提供的位置信息,然后再加上一些控制算法就可以实现机器人的精密运动啦

官方还贴心地给了例程 https://github.com/stereolabs/zed-ros-examples/tree/master/tutorials , 注释好像还不少,爱了爱了?

小提示:要想正确运行例程,别忘了将它添加到ros工作空间中并且编译通过哦,当然如果你成功运行了roslaunch zed_display_rviz display_zedm.launch,那么说明你已经正确编译了,哈哈

ps:博主是个ros初学者,工程经验有限,有说的不对的地方还望海涵?

5.1 zed_tracking_sub_tutorial

这个文件的例程就是告诉我们如何获得位置信息

查看zed_tracking_sub_tutorial.cpp,原本例程里是订阅的话题是"/zed/zed_node/...",现在我用的是zed mini,因此要做个改动,即zed改成zedm,这是zed-ros-wrapper里关于zed mini定义的话题名字,具体改动如下:

  /**
   * The subscribe() call is how you tell ROS that you want to receive messages
   * on a given topic.  This invokes a call to the ROS
   * master node, which keeps a registry of who is publishing and who
   * is subscribing.  Messages are passed to a callback function, here
   * called imageCallback.  subscribe() returns a Subscriber object that you
   * must hold on to until you want to unsubscribe.  When all copies of the Subscriber
   * object go out of scope, this callback will automatically be unsubscribed from
   * this topic.
   *
   * The second parameter to the subscribe() function is the size of the message
   * queue.  If messages are arriving faster than they are being processed, this
   * is the number of messages that will be buffered up before beginning to throw
   * away the oldest ones.
   */
  ros::Subscriber subOdom = n.subscribe("/zedm/zed_node/odom", 10, odomCallback);
  ros::Subscriber subPose = n.subscribe("/zedm/zed_node/pose", 10, poseCallback);

然后在启动zed-ros-wrapper的各个节点后,即使用zedm.launch后,我们在启动这个例程节点

rosrun zed_tracking_sub_tutorial zed_tracking_sub

可以看到,该节点输出的一些信息

5.2 geometry_msgs/PoseStamped

geometry_msgs/PoseStamped是 ros 的一个消息类型

http://docs.ros.org/en/noetic/api/geometry_msgs/html/msg/PoseStamped.html
https://docs.ros.org/en/diamondback/api/geometry_msgs/html/msg/PoseStamped.html

zed-ros-wrapper使用了这个消息类型,来输出位置信息

默认是map-frames,即空间坐标系,也就是说,在zed开机后,SDK运行,此时zed会以当前的位置为原点,建立map坐标系并固定下来。

map坐标系符合FLU(前左上)坐标系的规则,前是指摄像头的朝向。

5.3 nav_msgs/Odometry

zed-ros-wrapper也使用了这个消息类型,来输出位置信息

http://docs.ros.org/en/noetic/api/nav_msgs/html/msg/Odometry.html

该消息理论上是里程计下计算的空间位置和速度,

默认坐标系是odometry frames,里程计坐标系,在zed的开机时,该坐标系应该和map坐标系重合,然后随着里程计误差的自我修正,该坐标系可能会发生移动。即产生误差。

该消息数据的特点是变化平缓,适合放在较为细微场景下使用,如避障等。