本文主要是介绍ROS机器人开机自启动(systemd 版本),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
配置/etc/rc.local的内容如下:
#!/bin/bash -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.
source /opt/ros/kinetic/setup.bash
source ~/zfak_ws/install/setup.bashecho "y" | rosclean purge
du -sh ~/.ros#-------------------Route Model--------------------#
export ROS_IP=192.168.1.101
export ROS_HOSTNAME=$ROS_IP
export ROS_MASTER_URI=http://192.168.1.101:11311
#--------------------------------------------------##-------------------Default WS---------------------#
cd ~/zfak_ws/install/lib/system_scripts
echo 4 | ./start_choose.sh
#--------------------------------------------------#exit 0
注意:原始的为/bin/sh -e,ROS的应该修改为 /bin/bash -e.
在 /lib/systemd/system/rc-local.service 的【service】中添加User属性为你当前登录的session,如果不设置,默认使用的是root。完整内容如下:
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.# This unit gets pulled automatically into multi-user.target by
# systemd-rc-local-generator if /etc/rc.local is executable.
[Unit]
Description=/etc/rc.local Compatibility
ConditionFileIsExecutable=/etc/rc.local
After=network.target[Service]
Type=forking
User=jld
ExecStart=/etc/rc.local start
TimeoutSec=0
RemainAfterExit=yes
其中jld为你当前登录的session.
-------------------------------------开机自动启动遇到最大的坑-------------------------------------------------
1.bash和sh的区别
在shell脚本的开头往往有一句话来定义使用哪种sh解释器来解释脚本。
2.bad file descriptor
最开始在ubuntu desktop版本可以通过Startup Applications配置sh脚本能够正常启动机器人所需要的所有进程(包括:定位、导航、激光、串口交互等),但是使用ubuntu server后没有Startup Applications,所以需要更换一种开机自启动的策略,所以选择Systemd。
然后,遇到了问题。在/etc/rc.local中配置sh脚本,其中两个进程都存在打开串口失败的问题。最开始把该问题归结于权限的问题,查找了几天,参考了stackoverflow的问题描述等。
链接:c++ - Opening /dev/ttyUSB0 returns "Bad file descriptor" - Stack Overflow
后来尝试使用root编译catkin_ws,给串口交互的这个Node节点赋予root权限。还是同样的错误。
bad file descriptor
也尝试其他自启动的方式:How to run ROS on startup (bootup),发现和我的策略以及实现方式一样。
链接:https://blog.roverrobotics.com/how-to-run-ros-on-startup-bootup/
实在想不出哪个地方有问题了,难道是我不清楚systemd的启动顺序和流程,(确实不清楚)
是不是系统开机自启动的时候,串口还没有准备好,roslaunch就去打开这个串口设备,导致bad file descriptor。
也有可能,是吧???
最终,我开始去从代码端入手去查找问题,先看打印perror的地方在哪里?哪一部分导致了这个错误。
open串口正常,设置串口属性的位置出错,说明fd不正常。往前查。。。fd来自于哪里?
if (tcgetattr(fd,&newtio) < 0) {perror("tcgetattr error");return -1;
}
原始返回fd的代码,如下:
int open_port(char *comport)
{int fd;fd = open(comport, O_RDWR|O_NOCTTY|O_NDELAY);if (-1 == fd){perror("Can't Open Serial Port");return(-1);}if(fcntl(fd, F_SETFL, 0)<0)printf("fcntl failed!\n");else//printf("fcntl=%d\n",fcntl(fd, F_SETFL,0));if(isatty(STDIN_FILENO)==0)printf("standard input is not a terminal device\n");else//printf("isatty success!\n");//printf("fd-open=%d\n",fd);return fd;
}
看着有啥问题没有?仔细分析这个open_port函数到底有没有问题。
----------------------------------------更新-------------2020/10/26----------------
树莓派自启动相关: (虽然我没有测试过,但和我的想法一样, 可行)
Raspberry Pi Documentation - Using Linux
Raspberry Pi Documentation - Using Linux
这篇关于ROS机器人开机自启动(systemd 版本)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!