机器人操作系统ROS—树莓派Pi4B+激光雷达SLAM建图环境搭建(Ubuntu20.04.3 + ROS Noetic)

之前学习ros,nvidia jetson nano板子装的ubuntu18.04系统比较正常,但是pi4b的板子装的raspberry系统会出现各种依赖问题。最近想充分利用下几块Pi4B的板子,反复试了pi4安装官方/非官方的ubuntu18.04.5+ROS Melodic版本,最终都会卡在map-server或rviz等依赖上。最终用Pi4B + Ubuntu20.04.3 + ROS Noetic + RpLidar安装测试成功,记录一下安装过程。

一、Ubuntu镜像烧制

准备好PI4B板子、SD卡、USB读卡器、显示器、无限键鼠,外加一台烧制用的电脑,这里我用的一个ubuntu的开发本。

1.准备烧制软件

a.安装Raspberry Pi Imager

安装树莓派官方的烧制软件Raspberry Pi Imager,我用的本身是linux,可以直接命令安装:

sudo snap install rpi-imager

其他操作系统可以自行下载对应版本:

app安装完是树莓派的icon,找到后启动:

2.烧制镜像

a.选择镜像

点击“CHOOSE OS”,选择“Other general-purpose OS” —“Ubuntu”—“Ubuntu Server 20.04.3”,选中arm64的版本(会自动下载对应镜像文件,不用自己单独下载):

b.选择SD卡

点击“CHOOSE STOGAGE”,选择要烧制的SD卡后,点击“WRITE”即可。

*注意:这里下载并烧制的速度很慢,感觉至少1-2个小时左右,实在熬不动了睡了,第二天早上起来看烧制完毕了…

3.系统初始化

a.初始化密码

sd卡插入pi4,接上键鼠、显示器,启动系统,初始用户名和密码都是ubuntu,第一次登录会强制修改密码。

你也可以创建一个自己习惯的用户:

# 添加work用户
sudo adduser -m work
# 添加权限
sudo vim /etc/sudoers
  work ALL=(ALL) ALL
sudo usermod -aG sudo,adm,dialout,cdrom,floppy,audio,dip,video,plugdev,lxd,netdev work
# 查看权限
id work
# 切换用户
su work

b.安装桌面

因为安装的是server版,为了方便操作,我们还需要安装桌面:

# 更新
sudo apt update
sudo apt upgrade
# 安装桌面
sudo apt install -y ubuntu-desktop

4.远程管理

a.远程桌面

设置里配置wiki之后,从官网下载安装nomachine arm64版本,之后就可以脱离显示器和键鼠,通过路由器查看ip后直接ssh或nomachine操作即可。

sudo dpkg -i nomachine_7.6.2_3_arm64.deb 

b.异地组网

推荐使用teamviewer免费版(非商业用途),当然你还可以安装ZeroTier(自测稳定性没有teamviewer好),登录并创建私有网络,在板子里join后,你就可以在非局域网直接链接到板子:

# linux下一键安装
curl -s https://install.zerotier.com | sudo bash
# 加入自己创建的私有网络
zerotier-cli join a09acf02339e3f97 

c.科学上网

设置“network”自动网络代理,配置.pac文件地址,以避免后边某些包无法下载。

 

二、安装ROS Noetic

1.安装ros noetic

因为melodic仅支持18.04,ROS1里只有noetic支持ubuntu20.04,所以我们这里安装noetic版本:

# 配置ros源(ustc的源最好最快)
#sudo sh -c 'echo "deb [arch=$(dpkg --print-architecture)] http://packages.ros.org/ros/ubuntu $(lsb_release -cs) main" > /etc/apt/sources.list.d/ros-latest.list'
sudo sh -c '. /etc/lsb-release && echo "deb [arch=$(dpkg --print-architecture)] http://mirrors.ustc.edu.cn/ros/ubuntu/ $DISTRIB_CODENAME main" > /etc/apt/sources.list.d/ros-latest.list'
# 添加公钥
sudo apt-key adv --keyserver 'hkp://keyserver.ubuntu.com:80' --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654
# 或  curl -s https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | sudo apt-key add -
# 安装ros桌面版
sudo apt update
sudo apt install ros-noetic-desktop   #桌面完整版-desktop-full;桌面版-desktop;基础版-ros-base
# 安装slam包
sudo apt install ros-noetic-slam-gmapping  ros-noetic-map-server


# 设置环境
echo "source /opt/ros/noetic/setup.bash" >> ~/.bashrc
source ~/.bashrc

# 安装编译依赖
sudo apt install python3-rosdep python3-rosinstall python3-rosinstall-generator python3-wstool build-essential 
# 初始化 rosdep
sudo apt install python3-rosdep
sudo vim /etc/hosts
    185.199.110.133  raw.githubusercontent.com
sudo rosdep init
rosdep update

2.安装编译环境并测试激光雷达

# 准备编译目录
mkdir -p ~/catkin_ws/src
cd catkin_ws/src/
# 克隆RPLIDAR ROS代码库(记得添加板子的ssh key到github)
git clone git@github.com:robopeak/rplidar_ros.git
# 编译
cd ~/catkin_ws
catkin_make

# source
echo "source /home/work/catkin_ws/devel/setup.bash" >> ~/.bashrc
source ~/.bashrc
echo $ROS_PACKAGE_PATH

# 启动激光雷达节点
roscore
rosrun rplidar_ros rplidarNode
或
roslaunch rplidar_ros view_rplidar.launch

# 查看激光雷达数据
rostopic list
rostopic echo /scan

# PC可视化点云数据,须去掉rplidarNode的启动
roscd rplidar_ros/launch/
cp view_rplidar.launch view_rplidar_robot.launch # 修改robot文件,把rplidar.launch注释掉,以免PC本地启动rplidar节节点
roslaunch rplidar_ros view_rplidar_robot.launch

# 查看topic
rostopic list
# 查看节点关系
rqt_graph

开启rviz后,相比于单独启动rplidarNode,会多出几个topic:

  • /initialpose:初始位姿
  • /move_base_simple/goal:全局路径规划目标位置
  • /scan:rplidar发布的激光雷达扫描数据
  • /tf、/tf_static:用于激光雷达坐标系、基坐标系、里程计坐标系之间的相互变换

可以看到rplidarNode发出/scan雷达数据topic:

3.测试slam建图

参考:机器人操作系统ROS—使用激光雷达RpLidar A1进行SLAM定位建图 #四、使用激光雷达进行SLAM定位建图

# 定位与地图管理工具
sudo apt install ros-noetic-fake-localization ros-noetic-map-server 
# hector 不需要里程计数据,只根据激光信息即可构建地图
sudo apt install ros-noetic-hector-slam ros-noetic-hector-slam-launch 
# gmapping 需要IMU+里程计+激光信息构建地图
sudo apt install ros-noetic-gmapping ros-noetic-slam-gmapping
# karto
sudo apt install ros-noetic-open-karto ros-noetic-slam-karto

# 克隆slam+导航代码库
cd catkin_ws/src/
git clone git@github.com:yanjingang/robot_navigation.git
# 编译
cd ~/catkin_ws
catkin_make

# SLAM建图测试
roslaunch robot_navigation robot_slam_laser.launch
# PC端可视化
roslaunch robot_navigation slam_rviz.launch

# 查看topic
rostopic list
# 查看节点关系
rqt_graph

# 保存地图
roscd robot_navigation/maps/
rosrun map_server map_saver -f map

开启slam建图后,相比于view_rplidar,会多出几个topic:

  • /initialpose:初始位姿
  • /map/map_metadata:hector发布的地图栅格数据、地图数据Meta
  • /move_base_simple/goal:全局路径规划目标位置
  • /poseupdate/slam_out_pose:hector发布的当前机器人位姿估计(高斯估计、无协方差两种)
  • /scan:rplidar发布的激光雷达扫描数据
  • /syscommand:hector订阅的系统命令(例如reset等)
  • /tf、/tf_static:用于激光雷达坐标系、基坐标系、里程计坐标系之间的相互变换

可以看到SLAM节点hector_height_mapping监听和发布的topic情况:

三、pi ros与arduino底盘的导航控制

pi ros+arduino底盘的导航控制原理:

1.测试导航

首先我们需要先通过测试导航包来搞清楚“定位-规划-控制”相关的topic及发送和监听关系:

# 导航功能包 (包含move_base导航+amcl定位+teb规划+键盘控制发送vel_cmd)
sudo apt install ros-noetic-navigation  ros-noetic-teb-local-planner ros-noetic-teleop-twist-keyboard

# pi上启动TEB planner,用于无地图场景导航并建图
roslaunch robot_navigation robot_slam_laser.launch planner:=teb
# pc端启动rviz查看建图数据和“2D Nav Goal”控制机器人移动
roslaunch robot_navigation slam_rviz.launch
# pc键盘控制
rosrun teleop_twist_keyboard teleop_twist_keyboard.py

# 查看topic(hector—slam负责建图,move_base负责路径规划,amcl负责定位)
rostopic list
    /cmd_vel         # move_base发布给底盘的移动速度命令
    /initialpose     # amcl定位初始位姿,可通过rviz控制栏的"2D Pose Estimate"按钮测试修正此值
    /map             # hector-slam发布的地图栅格数据,amcl/move_base都会订阅用于定位和路径规划
    /map_metadata    # hector-slam发布的地图数据Meta
    /move_base/current_goal 
    /move_base/goal  # move_base监听的规划目标,可通过rviz的“2D Nav Goal”按钮测试发送
    /move_base_simple/goal   # 同上,但是非action接口,无法追踪目标状态
    /poseupdate      # hector-slam发布的当前机器人位姿估计(具有高斯估计的不确定性)
    /rosout
    /rosout_agg
    /scan            # rplidar发布的激光雷达数据
    /slam_cloud
    /slam_out_pose   # hector-slam发布的当前机器人位姿估计(没有协方差)
    /syscommand      # hector-slam订阅的系统命令,例如reset
    /tf              # 用于激光雷达坐标系、基坐标系、里程计坐标系之间的相互变换
    /tf_static      

# 查看节点关系
rqt_graph

# 点击rviz控制栏里的"2D Pose Estimate"修正初始位姿按钮,同时监听初始位姿topic,可以看到修正初始位姿数据
rostopic echo /initialpose
    header: 
      seq: 0
      stamp: 
        secs: 1637590180
        nsecs: 619881730
      frame_id: "map"
    pose: 
      pose: 
        position: 
          x: 0.898611545563
          y: -0.214766919613
          z: 0.0
        orientation: 
          x: 0.0
          y: 0.0
          z: 0.364361599826
          w: 0.931257550075
      covariance: [0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.06853892326654787]
    ---

# 点击rviz控制栏里的"2D Nav Goal"设定导航目标按钮,同时监听对应topic,可以看到修正初始位姿数据
rostopic echo /move_base/goal
    header: 
      seq: 2
      stamp: 
        secs: 1637592510
        nsecs: 186612710
      frame_id: ''
    goal_id: 
      stamp: 
        secs: 0
        nsecs:         0
      id: ''
    goal: 
      target_pose: 
        header: 
          seq: 2
          stamp: 
            secs: 1637592510
            nsecs: 182121126
          frame_id: "map"
        pose: 
          position: 
            x: 0.610744893551
            y: 0.824579000473
            z: 0.0
          orientation: 
            x: 0.0
            y: 0.0
            z: 0.564671369508
            w: 0.825315845272
    ---

截止到这里,我们基本弄明白了“slam-定位-规划-控制-底盘”之间的topic关系,也进行了模拟的导航测试,但是目前我们的ros跟底盘之间还并没有建立连接和联动(ros未拿到底盘的里程计数据,也没有把move指令发送给底盘),所以我们下一步需要打通pi ros与arduino 底盘的连接,并使move_base与arduino联动起来。

2.控制机构

a.打通pi ros与arduino的基本通讯能力

机器人操作系统ROS—Arduino执行机构

b.base_control底盘的cmd_vel通信

# 添加base_control
vim launch/robot_lidar.launch
  <!-- base control -->
  <include file="$(find robot_navigation)/launch/base_control.launch" />

# 绑定底盘端口
 vim launch/base_control.launch
<launch>
    ...
    <!-- serial param -->
    <arg name="port" default="/dev/ttyACM0" />
    <arg name="baudrate" default="57600" />
    ...
</launch>

# 编写双向通信测试代码
vim script/base_control.py
#代码详见 https://github.com/yanjingang/robot_navigation

# 单独验证sub/pub
rosrun rosserial_python serial_node.py _port:=/dev/ttyACM0
python script/base_control.py

# 合并验证建图
roslaunch robot_navigation base_control.launch
roslaunch robot_navigation robot_slam_laser.launch planner:=teb
roslaunch robot_navigation slam_rviz.launch   #pc

# 使用地图导航测试
roslaunch robot_navigation robot_navigation.launch
roslaunch robot_navigation navigation_rviz.launch  #pc

# 查看节点和topic关系
rqt_graph
# 查看topic
rostopic list
    /initialpose     # amcl定位初始位姿,可通过rviz控制栏的"2D Pose Estimate"按钮测试修正此值
    /amcl/parameter_descriptions
    /amcl/parameter_updates
    /amcl_pose      # amcl发布的机器人在地图中的位姿估计,带有协方差信息
    /clicked_point
    /cmd_vel         # move_base发布给底盘的移动速度命令
    /debug
    /diagnostics
    /map             # amcl订阅的地图栅格数据,用于定位和路径规划
    /map_metadata    # 地图数据Meta
    /map_updates
    /move_base/DWAPlannerROS/cost_cloud
    /move_base/DWAPlannerROS/global_plan
    /move_base/DWAPlannerROS/local_plan
    /move_base/DWAPlannerROS/trajectory_cloud
    /move_base/GlobalPlanner/parameter_descriptions
    /move_base/GlobalPlanner/parameter_updates
    /move_base/GlobalPlanner/plan
    /move_base/GlobalPlanner/potential
    /move_base/GlobalPlanner/potential_updates
    /move_base/TebLocalPlannerROS/global_plan
    /move_base/TebLocalPlannerROS/local_plan
    /move_base/TebLocalPlannerROS/obstacles
    /move_base/TebLocalPlannerROS/parameter_descriptions
    /move_base/TebLocalPlannerROS/parameter_updates
    /move_base/TebLocalPlannerROS/teb_feedback
    /move_base/TebLocalPlannerROS/teb_markers
    /move_base/TebLocalPlannerROS/teb_poses
    /move_base/TebLocalPlannerROS/via_points
    /move_base/cancel
    /move_base/current_goal
    /move_base/feedback
    /move_base/global_costmap/costmap
    /move_base/global_costmap/costmap_updates
    /move_base/global_costmap/footprint
    /move_base/global_costmap/inflation_layer/parameter_descriptions
    /move_base/global_costmap/inflation_layer/parameter_updates
    /move_base/global_costmap/obstacle_layer/clearing_endpoints
    /move_base/global_costmap/obstacle_layer/parameter_descriptions
    /move_base/global_costmap/obstacle_layer/parameter_updates
    /move_base/global_costmap/parameter_descriptions
    /move_base/global_costmap/parameter_updates
    /move_base/global_costmap/static_layer/parameter_descriptions
    /move_base/global_costmap/static_layer/parameter_updates
    /move_base/goal  # move_base监听的规划目标,可通过rviz的“2D Nav Goal”按钮测试发送
    /move_base/local_costmap/costmap
    /move_base/local_costmap/costmap_updates
    /move_base/local_costmap/footprint
    /move_base/local_costmap/obstacle_layer/parameter_descriptions
    /move_base/local_costmap/obstacle_layer/parameter_updates
    /move_base/local_costmap/parameter_descriptions
    /move_base/local_costmap/parameter_updates
    /move_base/local_costmap/static_layer/parameter_descriptions
    /move_base/local_costmap/static_layer/parameter_updates
    /move_base/parameter_descriptions
    /move_base/parameter_updates
    /move_base/result
    /move_base/status
    /move_base_simple/goal   # 同上,但是非action接口,无法追踪目标状态
    /odom
    /particlecloud   # amcl发布的 粒子滤波器维护的位姿估计集合
    /path_point
    /rosout
    /rosout_agg
    /scan            # rplidar发布的激光雷达数据
    /tf              # 用于激光雷达坐标系、基坐标系、里程计坐标系之间的相互变换
    /tf_static
# 查看base_control发送的轮速数据
rostopic echo /odom

# 测试"2D Nav Goal",查看base_control收到的指令数据
rostopic echo /cmd_vel
    linear: 
      x: 0.0
      y: 0.0
      z: 0.0
    angular: 
      x: 0.0
      y: 0.0
      z: 0.0
    ---
robot_navigation.launch下能看到base_control.py里收到的/cmd_vel
    [INFO] [1638249681.414300]: get cmd data:linear: 
      x: 0.10077160733559222
      y: 0.0
      z: 0.0
    angular: 
      x: 0.0
      y: 0.0
      z: -0.19502660300177715

各节点的关系如下图:

  • rplidar节点发布/scan,mapserver节点发布/map;
  • amcl定位节点订阅了上述topic以及初始位姿/initialpose,并发布机器人位姿估计/amcl_pose;
  • movebase导航节点订阅了/scan和/map以及规划目标后,发布/cmd_vel运动指令;
  • serial底盘节点监听/cmd_vel指令并执行运动,同时发布debug信息给base_control;
  • base_control监听底盘的/debug,并发布底盘/odom里程计信息给movebase节点以帮助定位;

c.完善arduino底盘指令执行逻辑

方案1:Arduino直接监听ROS的/cmd_vel,并发送速度信息,ROS端组织/odom

这里我们用arduino底盘通过rosserial直接监听/cmd_vel并通过pid模拟信号控制电机转动的方式实现,其中的核心工作是解析Twist格式控制指令中的线速度和角速度,控制底盘完成相应运动。

stydy/iot/arduino/pid/pid.ino

arduino板子算力有限(存储30k,内存2k),监听cmd_vel后如果试图直接发送/odom会提示内存不足,所以此方案的/odom需要放到ROS端,通过base_control.py监听底盘的/debug topic监控底盘状态并组织odom。

方案2:所有topic逻辑放在ROS 设备上,降低Arduino算力不足的压力

与方案1的rosserial不同的是,ros_arduino_bridge的firmware对PWM计算、电机编码信号计数、与上位机的消息收发进行了较好的封装,几乎通过配置即可实现arduino端逻辑;上位机的base_control.py也封装了/cmd_vel监听和/odom发送逻辑,并与firmware通过裸serial通信。这种方式对底盘板子的算力要求较低。

具体方法参考下文的“三、编码电机的控制与编码器数据读取”部分

小猪学arduino—使用L298驱动版控制两个直流电机

d.完善base_control的里程计/odom计算和上报逻辑

arduino板子算力有限(存储30k,内存2k),监听cmd_vel后内存不足…odom里程计的计算发布必须放在上位机上。

odom主要包含pose坐标和twist运动速度两部分信息:

同上,建议使用ros_arduino_bridge,具体连接方法:

  • 电机电源+正-负极(红/白线):接L298 output 1/2或3/4口(供电+驱动板控制)
  • L298 input(控制口):接arduino D7/D8口(用于电机运动控制)
  • 电机编码器电源+正-负极(黑/蓝线):接arduino VIN+GND口(供电)
  • 电机编码器信号(黄/绿线):接arduino D3/D4口(用于电机编码器信息读取)

说明文档和代码放到https://github.com/yanjingang/ros_arduino_bridge了,具体使用方法如下:

# pc/pi安装 ros_arduino_bridge 库
cd ~/catkin_ws/src
git clone git@github.com:yanjingang/ros_arduino_bridge.git
cd ~/catkin_ws
catkin_make
source ~/catkin_ws/devel/setup.bash

#arduino 
#烧制OSArduinoBridge.ino到板子上

# pc/pi启动测试
roslaunch ros_arduino_python arduino.launch

# 尝试发布 Twist 命令:
rostopic pub /cmd_vel geometry_msgs/Twist -r 1 -- '[2.0, 0.0, 0.0]' '[0.0, 0.0, 1.8]'
rostopic pub -1 /cmd_vel geometry_msgs/Twist '{ angular: {z: 1} }'

# 查看里程计数据:
rostopic echo /odom

# 如果发布Twist后里程计数为0或/odom坐标不变,检查下编码器的电源和信号接线是否正确
get_encoder_counts: [0, 0]


# 修改base_control配置,使用ros_arduino_python里的base_control
vim ~/catkin_ws/src/robot_navigation/launch/robot_lidar.launch
 <!--include file="$(find robot_navigation)/launch/base_control.launch"><arg name="pub_imu" value="$(arg pub_imu)"/> </include--> <node name="arduino" pkg="ros_arduino_python" type="arduino_node.py" output="screen"> <rosparam file="$(find ros_arduino_python)/config/my_arduino_params.yaml" command="load" /> </node> # 使用地图导航测试
roslaunch robot_navigation robot_navigation.launch
roslaunch robot_navigation navigation_rviz.launch  #pc

# 查看指令和里程计数据是否正常:
rostopic echo /cmd_vel
rostopic echo /odom

 

 

四、总结

安装过程中全程连接手机4G热点,除了raw.githubusercontent.com安装相对顺畅,所以如果大家因为各种网络问题,注意三种解决方法:

1.科学上网避免有些域名不能访问

2.手机4/5G热点网速更快(全部下来2-3G的流量)

3.域名如果怎么搞都不行,就在其他机器ping出IP地址,直接把IP配置到/etc/hosts中,跳过DNS过程

 

yan 21.10.17

 

参考:

How to install Ubuntu Desktop on Raspberry Pi 4

Ubuntu Server LTS 20.04 安装桌面

ROS Noetic installation instructions

清华大学开源软件镜像站-ubuntu arm

Getting Started With ROS Melodic on Raspberry Pi 4 Model B

Ubuntu 18.04 LTS (Bionic Beaver)

ROS小车启动功能包编写

move_base代码学习一

ROS机器人Diego 1#制作(二)Base Controller—Rosserial_arduino

TF坐标变换

译:在ROS上发布Odometry信息

ROS与Arduino:用Twist消息+用键盘+用Xbox one手柄 控制小车

基于rosserial_arduino的底盘实现_02电机转向控制

欢迎关注下方“非著名资深码农“公众号进行交流~

发表评论

邮箱地址不会被公开。