robot_upstart
机器人开发中,一般都要求工控机开机后要启动某些节点或launch,ROS已经考虑到了这个需求。专门开发了一个package叫做robot_upstart
,它提供脚本来安装和卸载随机启动的节点,但是经过很长时间的研究,发现这个包并不好用,需要额外很多设置。
安装: sudo apt-get install ros-kinetic-robot-upstart
,现在有一个package,名称是nav,在它的launch文件夹里有个launch文件叫做all.launch
,下面是第一个命令:1
rosrun robot_upstart install nav/launch/all.launch
这实际是把nav
做成了一个service
,就跟MySQL服务器一样,然后按照系统自动提示执行:1
sudo systemctl daemon-reload && sudo systemctl start foo
如果是普通节点,重新开机就能启动all.launch
所有节点了,但是我的程序用到了很多自定义的环境变量,结果自启动总是失败。
生成的文件
按上面官方流程执行产生了几个文件,到/etc/ros/kinetic
查看是否自启动的包有对应文件夹,里面是设定的launch文件,文件名就是启动名称
跟自启动服务相关的脚本是/usr/sbin/nav-start
,停止脚本是同目录的nav-stop
,内容比较复杂,也没有分析的必要了。
官方说自启动的日志文件在/var/log/upstart
,但是我试了试发现从来都没有,后来看了看nav-start
脚本,虽然没有完全看懂,但是在一定条件下会在/tmp
下创建日志.不过我看了看日志,在自启动节点失败时,也没有什么有用的信息.
两个service文件其实完全一样,而且只修改一个就可以,/lib/systemd/system/nav.service
的内容:1
2
3
4
5
6
7
8
9
10
11[Unit]
Description="bringup nav"
After=network.target
[Service]
Type=simple
EnvironmentFile=/etc/robotenv
ExecStart=/usr/sbin/nav-start
[Install]
WantedBy=multi-user.target
这里就是复杂的地方了,如果有自定义的环境变量,需要在执行rosrun robot_upstart install
后加到这里,再执行后面的启动服务命令。
我新建了一个文件/etc/robotenv
,里面定义环境变量:1
2MAP_FILE=/home/user/maps
BAG_FILE=/home/user/bags
不要加export,否则无法生效。然后用EnvironmentFile=/etc/robotenv
调用,而且这句应当在ExecStart
之前
但是在启动跟串口有关的节点时发现失败了,虽然我之前已经对串口进行了永久使能,但在开机过程中可能需要重新使能,问题在于串口使能前先启动了节点,结果失败。所以在rc.local
中添加:1
2chmod 777 /dev/ttyS0
chmod 777 /dev/ttyS1
停止开机启动:rosrun robot_upstart uninstall nav
,会删除除了/tmp
里几个文件的其他所有文件
问题
在小强机器人上对startup.launch
开机启动,在另一台电脑上执行rosnode list
和rostopic list
都是正常的,但rostopic echo
却没有结果,rosnode ping
也不行。把所有ROS关闭,重启startup.launch,又正常了。
rc.local,只用于无界面节点
如果启动的节点比较简单,可以用rc.local
的方式,在文件里添加roslaunch命令和环境变量即可,需要注意的是下面的失败的情况
环境变量
第一次开机启动后,节点都启动了,但发现一些节点不能正常运行,后来发现是一些节点中还使用了自定义的环境变量,比如某些目录的地址,所以把这些也要加上:1
2
3export CONFIG_PATH=/home/`hostname`/workspace/config
export MAP_FILES_PATH=/home/`hostname`/data
export LAUNCH_PATH=/home/`hostname`/workspace/src
mini-httpd用到的所有环境变量也要加入到rc.local
当中,因为开机时加载的环境变量不是bashrc
的,而是rc.local
脚本出错
编辑/etc/rc.local
进行程序自启动时没有生效。可能是脚本出错,脚本第一行为#!/bin/sh -e
,-e标志脚本如果有错误,就不再向下执行。加入下面内容,可以检查错误的原因:1
2
3exec 2> /tmp/rc.local.log # send stderr from rc.local to a log file
exec 1>&2 # send stdout to the same log file
set -x # tell sh to display commands before execution
错误日志都在log文件里,第二行是把一般输出也放了进去,有时会很多,这行可以不加。
打开错误日志发现source not found
,不识别source,这是shell的原因。把第一行改为#!/bin/bash
,也就是换成bash,最终生效了。
权限和服务
有时按上面步骤还是失败,那么进行下面操作:1
2
3
4sudo chmod +x /etc/rc.local
# rc.local被认为是服务,默认是关闭的,需要打开
sudo systemctl enable rc-local.service
重启
完整脚本如下:1
2
3
4
5
6
7
8
9
10
11exec 2> /tmp/rc.local.log # send stderr from rc.local to a log file
#exec 1>&2 # send stdout to the same log file
set -x
source /opt/ros/kinetic/setup.bash
source /home/user/name/workspace/devel/setup.bash
export ROS_IP=`hostname -I`
export ROS_HOSTNAME=`hostname -I`
export ROS_MASTER_URI=http://192.168.73.14:11311
roslaunch /home/user/name/workspace/src/package/launch/start.launch & mini_httpd -C /etc/mini_httpd.conf # 同一行
exit 0
只启动了一个launch文件
在rc.local
设置开机启动,最好只有一个launch,否则常常只启动一个,我们可以把所有launch放到一个里面.
启动roslaunch失败
在rc.local
中启动launch文件用的是roslaunch ~/Robot/workspace/package/bringup.launch
,结果失败,查看日志发现实际路径是/root/Robot/workspace/package/bring.launch
,可见开机时Linux不能把~
识别为/home/user
gnome-session-properties,只用于有界面(带显示器)节点
以上方法用于普通ROS程序没问题,但带界面的程序就失灵了。这种情况下先新建一个脚本,比如test.sh
:1
2
3
4
5
6
7
8
9
10
echo -----------准备开机自启动程序 robot-----------
sleep 10
source /opt/ros/kinetic/setup.sh
source /home/user/work/workspace/devel/setup.bash
export ROS_IP=`hostname -I`
export ROS_HOSTNAME=`hostname -I`
export ROS_MASTER_URI=http://192.168.31.14:11311
rosrun robot robot
注意文件要给权限 ,sleep 10
是让脚本阻塞10秒钟,因为程序需要等待与roscore的通信,如果不阻塞,可能会先于roscore启动节点,导致失败而退出,其他就是加载需要的环境和执行程序。
然后在终端输入gnome-session-properties
,打开应用程序首选项设置开机启动程序。
在命令
中填写gnome-terminal -x /path/test.sh
。保存后重启,会出现一个终端执行脚本中的命令
这种方法只适用于有界面的情况,假如机器不带显示器,就无法启动成功。 最好每个节点就要对应一个sh文件,逐个添加。因为都放在一起会阻塞在第一个节点,退出以后会接着执行下一个,不能同时执行