之前学习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的基本通讯能力
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通信。这种方式对底盘板子的算力要求较低。
具体方法参考下文的“三、编码电机的控制与编码器数据读取”部分
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
ROS Noetic installation instructions
Getting Started With ROS Melodic on Raspberry Pi 4 Model B
Ubuntu 18.04 LTS (Bionic Beaver)
ROS机器人Diego 1#制作(二)Base Controller—Rosserial_arduino
ROS与Arduino:用Twist消息+用键盘+用Xbox one手柄 控制小车
基于rosserial_arduino的底盘实现_02电机转向控制