<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:wfw="http://wellformedweb.org/CommentAPI/">
<channel>
<title>一世繁华 - ROS</title>
<link>https://blog.hantaotao.top/tag/ROS/</link>
<atom:link href="https://blog.hantaotao.top/feed/tag/ROS/" rel="self" type="application/rss+xml" />
<language>zh-CN</language>
<description></description>
<lastBuildDate>Thu, 22 Aug 2024 20:58:00 +0800</lastBuildDate>
<pubDate>Thu, 22 Aug 2024 20:58:00 +0800</pubDate>
<item>
<title>ROS相关基础 （Updated:20241027）</title>
<link>https://blog.hantaotao.top/archives/136/</link>
<guid>https://blog.hantaotao.top/archives/136/</guid>
<pubDate>Thu, 22 Aug 2024 20:58:00 +0800</pubDate>
<dc:creator>小韩</dc:creator>
<category><![CDATA[笔记本]]></category>
<description><![CDATA[1. linux基础1.1 pwd查看当前所在目录1.2 cd进行目录的切换1.3 mkdir创造文件夹mkdir XXXXXX为创建的文件夹的名字1.4 ls列出当前文件下有的文件或文件夹1....]]></description>
<content:encoded xml:lang="zh-CN"><![CDATA[
<h1>1. linux基础</h1><h2>1.1 pwd</h2><p>查看当前所在目录</p><h2>1.2 cd</h2><p>进行目录的切换</p><h2>1.3 mkdir</h2><p>创造文件夹</p><pre><code>mkdir XXX
XXX为创建的文件夹的名字</code></pre><h2>1.4 ls</h2><p>列出当前文件下有的文件或文件夹</p><h2>1.5 touch</h2><p>创建一个文本文件</p><pre><code>touch XXX
XXX为所创建的文件名</code></pre><h2>1.6 mv</h2><p>移动一个文件到另一个文件夹下</p><pre><code>mv XX /XXX
其中XX是文件名字
/XXX是文件的路径</code></pre><h2>1.7 cp</h2><p>复制一个文件到指定路径下</p><pre><code>cp XX XXX/XXXX
其中XX是文件名字
XXX是文件新的路径
XXXX是文件新的名字 如果希望重命令的话，如果不需要，则不需要后面的命令</code></pre><h2>1.8 rm</h2><p>删除文件</p><pre><code>rm XX
XX是文件名字</code></pre><p>如果想要删除文件夹的话，咋需要加-r与斜杠</p><pre><code>rm -r XXX/
其中XXX是文件夹名字</code></pre><h2>1.9 sudo</h2><p>提升用户命令</p><pre><code>sudo apt-get-update</code></pre><h2>1.10 help</h2><p>帮助指令</p><pre><code>--help

例如  sudo --help</code></pre><h2>1.11 clear</h2><p>用于清理终端上信息。<br>或者使用快捷键“ctrl+L”</p><h1>2. 安装g++与python</h1><pre><code>sudo apt-get install g++
sudo apt-get install python</code></pre><h1>3.ROS安装</h1><h2>ubuntu与ros版本对应关系</h2><p>| Ubuntu    | ROS 1.0     | ROS 2.0     |<br>| 16.04 LTS | Kinetic LTS | Ardent      |<br>| 18.04 LTS | Melodic LTS | Dashing LTS |<br>| 20.04 LTS | Noetic LTS  | Foxy LTS    |</p><h2>第1步 添加源</h2><p>使用阿里镜像源，以加快安装速度</p><pre><code>sudo sh -c &#039;. /etc/lsb-release &amp;&amp; echo &quot;deb http://mirrors.aliyun.com/ros/ubuntu/ `lsb_release -cs` main&quot; &gt; /etc/apt/sources.list.d/ros-latest.list&#039;
</code></pre><h2>第2步 设置密钥</h2><pre><code>sudo apt-key adv --keyserver &#039;hkp://keyserver.ubuntu.com:80&#039; --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654
</code></pre><h2>第3步 安装</h2><p>对源进行更新</p><pre><code>sudo apt-get update   </code></pre><p>安装ROS</p><pre><code>sudo apt install ros-melodic-desktop-full  </code></pre><p>查看可使用的包，以确定安装成功</p><pre><code>apt-cache search ros-melodic </code></pre><p>安装ros的时候可能出现依赖问题，这个时候可以安装那些依赖包</p><pre><code>sudo aptitude install ros-melodic-desktop ros-melodic-perception ros-melodic-simulators ros-melodic-urdf-sim-tutorial</code></pre><p>可能需要安装aptitude,aptitude 相比于apt更加智能，会进行建议相关</p><pre><code>sudo apt-get install aptitude </code></pre><p>aptitude的一些常用的操作：</p><pre><code>sudo aptitude update                   # 更新软件源
sudo aptitude search  软件名称          #  查看软件
sudo aptitude install 软件名称          #  安装软件
</code></pre><h2>第4步 配置环境</h2><p>rosdep 安装</p><pre><code>sudo apt-get install python-rosdep </code></pre><p>初始化rosdate</p><pre><code>sudo rosdep init
rosdep update  </code></pre><p>初始化环境变量</p><pre><code>echo &quot;source /opt/ros/melodic/setup.bash&quot; &gt;&gt; ~/.bashrc
source ~/.bashrc   </code></pre><p>安装rosdep时可能会出错，如果出错，就运行下面命令</p><pre><code>sudo apt install python-rosinstall python-rosinstall-generator python-wstool build-essential </code></pre><h2>第5步 验证ROS</h2><p>启动 ros master 即节点管理器</p><pre><code>roscore  </code></pre><p>新开一个终端，启动小海龟仿真器</p><pre><code>rosrun turtlesim turtlesim_node  </code></pre><pre><code>rosrun #功能包 #节点名字</code></pre><p>再新开一个终端，启动小海龟控制节点</p><pre><code>rosrun turtlesim turtle_teleop_key  </code></pre><p>再开一个终端，以查阅节点关系和话题列表</p><pre><code>rqt_graph  </code></pre><h2>一键脚本安装</h2><p>脚本命令待确定</p><pre><code>wget http://fishros.com/install -O fishros &amp;&amp; sudo ./fishros</code></pre><p>按照脚本提示进行安装即可</p><hr><h1>4.ROS相关框架与内容</h1><h2>4.1节点（Node）</h2><ul><li>执行具体任务的进程，独立运行的可执行文件。</li><li>不同节点可使用不同的编程语言，可分布式运行在不同的主机。</li><li>节点在系统中的名称必须是唯一的。</li></ul><h2>4.2 节点管理器（ROS Master）</h2><ul><li>为节点提供命名和注册服务。</li><li>跟踪和记录话题/服务，辅助节点相互查找、建立参数。</li><li>提供参数服务器，节点使用此服务器存储和检索运行时的参数。</li></ul><h2>4.3 话题（Topic）--异步通信机制</h2><ul><li>节点间用来传输数据的重要总线。</li><li>使用<strong>发布/订阅</strong>模型，数据由发布者传输到订阅者，同一个话题的订阅者或发布者可以不唯一。</li></ul><h2>4.4 消息（Message）--话题数据</h2><ul><li>具有一定的类型和数据结构，包括ROS提供的标准类型和用户自定义类型，是节点-话题-节点间传输数据的通道。</li><li>使用百年城语言无关.msg文件定义，编译过程中生成对应的代码文件。</li></ul><p>可以通过下面这张图来理解<strong>话题</strong>和<strong>消息</strong>，话题类似于一个消息驿站，需要投放消息的向里面投放，需要接收消息的，从里面接收；换一个比喻就是冒险者工会。<br><img src="http://image.hantaotao.top/image/2024/ROS/1025/Pastedimage20240811122825-min.png" alt="Pastedimage20240811122825-min.png||600" title="Pastedimage20240811122825-min.png||600"></p><h2>4.5 服务（Service）--同步通信机制</h2><ul><li>使用<strong>客户端/服务端（C/S）</strong> 模型，客户端发送<strong>请求</strong>数据，服务器完成处理后返回<strong>应答</strong>数据。</li><li>使用编程语言无关的.srv文件定义请求和应答数据结构，编译过程中生成对应的代码文件。</li><li><p>（需要区分话题和服务，话题发布出去，并不指定接收与回应，而服务是一对一的，有接收有回应。）<br><img src="http://image.hantaotao.top/image/2024/ROS/1025/Pastedimage20240811123754-min.png" alt="Pastedimage20240811123754-min.png||600" title="Pastedimage20240811123754-min.png||600"></p><h2>4.6 参数（Parameter）--全局共享字典</h2></li><li>可通过网络访问的共享、多变量字典；</li><li>节点使用此服务来存储和检索运行时的参数；</li><li>适合存储<strong>静态、非二进制</strong>的配置参数，不适合存储动态配置的数据。</li><li>（如果需要动态参数，ROS还有另外一个功能是<strong>动态参数配置</strong>，有需要的时候可以进行相关学习。）</li></ul><h2>4.7 文件系统</h2><p><img src="http://image.hantaotao.top/image/2024/ROS/1025/Pastedimage20240811124717-min.png" alt="Pastedimage20240811124717-min.png||600" title="Pastedimage20240811124717-min.png||600"></p><h3>4.7.1 功能包（Package）</h3><ul><li><p>ROS 软件中基本单元，包含节点源码、配置文件、数据定义等。</p><h3>4.7.2 功能包清单（Package manifest）</h3></li><li><p>记录功能包的基本信息，包含作者信息，许可信息，依赖选项，编译标志等。</p><h3>4.7.3 元功能包（Meta Package）</h3></li><li>组织多喝用于同一目标的功能包。</li></ul><h2>4.8 命令行工具</h2><h3>4.8.1 rosnode（节点工具）</h3><pre><code>    rosnode ping    test connectivity to node
    rosnode list    list active nodes
    rosnode info    print information about node 后面跟节点名字
    rosnode machine    list nodes running on a particular machine or list machines
    rosnode kill    kill a running node 后面跟节点的id号码
    rosnode cleanup    purge registration information of unreachable nodes
</code></pre><h3>4.8.2 rostopic(话题工具)</h3><pre><code>    rostopic bw    display bandwidth used by topic
    rostopic delay    display delay of topic from timestamp in header
    rostopic echo    print messages to screen
    rostopic find    find topics by type
    rostopic hz    display publishing rate of topic    
    rostopic info    print information about active topic
    rostopic list    list active topics
    rostopic pub    publish data to topic
    rostopic type    print topic or field type

Type rostopic &lt;command&gt; -h for more detailed usage, e.g. &#039;rostopic echo -h&#039;</code></pre><h3>4.8.3 rosservice(服务工具)</h3><pre><code>    rosservice args    print service arguments
    rosservice call    call the service with the provided args
    rosservice find    find services by service type
    rosservice info    print information about service
    rosservice list    list active services
    rosservice type    print service type
    rosservice uri    print service ROSRPC uri
</code></pre><h3>4.8.4 rosbag(数据存储、回放及修改)</h3><pre><code>rosbag &lt;subcommand&gt; [options] [args]
---
Available subcommands:
   check      Determine whether a bag is playable in the current system, or if it can be migrated.
   compress      Compress one or more bag files.
   decompress      Decompress one or more bag files.
   decrypt      Decrypt one or more bag files.
   encrypt      Encrypt one or more bag files.
   filter      Filter the contents of the bag.
   fix      Repair the messages in a bag file so that it can be played in the current system.
   help  
   info      Summarize the contents of one or more bag files.
   play      Play back the contents of one or more bag files in a time-synchronized fashion.
   record      Record a bag file with the contents of specified topics.
   reindex      Reindexes one or more bag files.</code></pre><p>举例</p><pre><code>rosbag record -a -O cmd_record</code></pre><p>其中 -a 表示记录所有数据，-O 表示数据存储的格式及名称<br>需要注意的是，默认数据存放的位置，是desktop位置</p><pre><code>rosbag play cmd_record</code></pre><p>即回访记录的数据。</p><h1>5.工作空间与功能包的创建</h1><h2>5.1 工作空间的创建</h2><ul><li>工作空间（workspace）是存放工程开发相关文件的文件夹。</li><li>src： 代码空间（source space）  源文件</li><li>build： 编译空间（build space ）编译过程中的中间文件，一般用不到</li><li>devel： 开发空间（development sapce） 可执行文件，库，脚本等</li><li>install： 安装空间（install space）安装成功的文件所在，devel与install中文件存在重复，在ROS2 中仅保留了install文件夹。</li></ul><p>创建工作空间</p><pre><code>mkdir catkin_ws
cd catkin_wa/
mkdir src
cd src/
catkin_init_workspace    //变化文件夹的属性，使之成为工作空间</code></pre><p>编译工作空间</p><pre><code>cd catkin_ws/     //回到工作空间跟目录
catkin_make  //进行编译，空文件夹也可以，会产生build 与devel 文件夹

catkin_make install   //会产生install文件夹，安装空间，安放可执行文件</code></pre><p>设置环境变量</p><pre><code>source devel/setup.bash</code></pre><p>检查环境变量路径，如有需要</p><pre><code>echo $ROS_PACKAGE_PATH</code></pre><h2>5.2 功能包的创建</h2><pre><code>catkin_create_pkg (package_name) (depend1) (depend2) (depend3) ...    // 创建功能包指令，依次是指定名字，指令需要依赖的库等</code></pre><p>e.g.</p><ul><li><p>创建功能包</p><pre><code>cd catkin_ws/src/     //即功能包一定要放在工作空间的src里面才是可以的。
catkin_create_pkg test_pkg std_msgs rospy rosapp</code></pre><ul><li>编译</li></ul></li></ul><pre><code>cd catkin_ws/       //进入工作空间
catkin_make          //执行编译
source devel/setup.bash          刷新 环境变量，使之生效。</code></pre><h1>6.发布者publisher编程实现</h1><h2>6.1 话题模型</h2><p><img src="http://image.hantaotao.top/image/2024/ROS/1025/Pastedimage20240831235803-min.png" alt="Pastedimage20240831235803-min.png||800" title="Pastedimage20240831235803-min.png||800"></p><h2>6.2 创建功能包</h2><pre><code>cd ~/catkin_ws/src
catkin_create_pkg learning_topic roscpp rospy std_msgs geometry_msgs turtlesim</code></pre><h2>6.3 创建发布者代码</h2><p>基本过程如下：</p><ul><li>初始化ROS节点；</li><li>向ROS Master注册节点信息，包括发布的话题名和话题中的消息类型；</li><li>创建消息数据；</li><li>按照一定频率循环发布消息。</li></ul><p>参考代码如下：<br>velocity _publisher.cpp</p><pre><code class="lang-c++"># include &lt;ros/ros.h&gt;
# include &lt;geometry_msgs/Twist.h&gt;

int main(int argc, char **argv)
{
    //ROS初始化
    ros::init(argc, argv, &quot;velocity_publisher&quot;);
    
    //创建节点句柄
    ros::NodeHandle n;
    
    //创建一个publisher, 发布名为/turtle1/cmd_vel的topic，消息类型为geometry_msgs::Twist,队列长度10
    ros::Publisher turtle_vel_pub = n.advertise&lt;geometry_msgs::Twist&gt;(&quot;/turtle1/cmd_vel&quot;, 10);
    
    //设置循环频率
    ros::Rate loop_rate(10);
    
    // 声明vel_msg在这里，而不是在循环内部
    geometry_msgs::Twist vel_msg;
    
    int count = 10;
    while(ros::ok())
    {
        // 初始化geometry_msgs::Twist消息的类型
        vel_msg.linear.x = 0.5;
        vel_msg.angular.z = 0.2;
        
        //发布消息
        turtle_vel_pub.publish(vel_msg);
        ROS_INFO(&quot;Publish turtle velocity command[%0.2f m/s, %0.2f rad/s]&quot;,
                 vel_msg.linear.x, vel_msg.angular.z);
        
        //设置循环频率延时
        loop_rate.sleep();
    }
    return 0;
}
</code></pre><h2>6.4 配置发布者代码编译规则</h2><p>配置CmakerLists.txt</p><ul><li>设置需要编译的代码和生成的可执行文件，例如，下面的就是将<strong>velocity_publisher.cpp</strong>这个代码文件编译成<strong>velocity_publisher</strong>这样一个可执行文件；</li><li><p>设置链接库，建立ROS里相关的链接库——。</p><pre><code class="lang-c++">add_executable(velocity_publisher src/velocity_publisher.cpp)
target_link_libraries(velocity_publisher ${catkin_LIBRARIES})</code></pre></li></ul><h2>6.5 编译并运行发布者</h2><pre><code>cd ~/catkin_ws
catkin_make
source devel/setup.bash
roscore
rosrun turtlesim turtlesim_node
rosrun learning_topic velocity_publisher</code></pre><hr><h1>7.订阅者Subscriber编程实现</h1><h2>7.1 话题模型</h2><p><img src="http://image.hantaotao.top/image/2024/ROS/1025/Pastedimage20240901204706-min.png" alt="Pastedimage20240901204706-min.png||600" title="Pastedimage20240901204706-min.png||600"></p><h2>7.2 创建订阅者代码</h2><p>下面是实现一个订阅者基本过程：</p><ul><li>初始化ROS节点；</li><li>订阅需要的话题；</li><li>循环等待话题消息，接收到消息后进入回调函数；</li><li>在回调函数中完成消息处理。</li></ul><p>下例将订阅/turtle1/pose话题，消息类型tuetlesim::Pose<br>pose_subscriber.cpp</p><pre><code class="lang-c++"># include &lt;ros/ros.h&gt;
# include &quot;turtlesim/Pose.h&quot;

//接收到订阅的消息后，进入消息回调函数，以及时调用处理

void poseCallback(const turtlesim::Pose::ConstPtr&amp; msg)

{
    //将接收到的消息打印出来，以进行排查

    ROS_INFO(&quot;Tuetle pose: x:%0.6f, y:%0.6f&quot;,msg-&gt;x, msg-&gt;y);
}

int main(int argc, char **argv)

{

    //初始化ROS节点

    ros::init(argc, argv, &quot;pose_subscriber&quot;);
    
    //创建节点句柄
    ros::NodeHandle n;

    //创建一个Subscriber，订阅名为/turtle/pose的topic，注册回调函数poseCallback
    ros::Subscriber pose_sub = n.subscribe(&quot;/turtle1/pose&quot;, 10, poseCallback);

    //循环等待回调函数

    ros::spin();
    return 0;
}</code></pre><h2>7.3 配置订阅者代码编译规则</h2><p>CMakerLists.txt</p><pre><code class="lang-c++">add_executable(pose_subscriber src/pose_subscriber.cpp)
target_link_libraries(pose_subscriber ${catkin_LIBRARIES})</code></pre><h2>7.4 编译并运行订阅者</h2><pre><code>cd ~/catkin_ws
catkin_maker
source devel/setup.bash
roscore
rosrun turtlesim turtlesim_node
rosrun learning_topic pose_subscriber

//为了让海龟动起来，运行键盘控制节点
rosrun turtlesim turtle_teleop_key</code></pre><h1>8.话题消息的定义与使用</h1><h2>8.1 话题模型</h2><p><img src="http://image.hantaotao.top/image/2024/ROS/1025/Pastedimage20240903233300-min.png" alt="Pastedimage20240903233300-min.png" title="Pastedimage20240903233300-min.png"></p><h2>8.2 自定义话题消息</h2><p>步骤：</p><ul><li>定义.msg文件；</li><li><p>在package.xml文件中添加功能包依赖；</p><pre><code class="lang-c++">&lt;build_depend&gt;message_generation&lt;/build_depend&gt;
&lt;exec_depend&gt;message_runtime&lt;/exec_depend&gt;</code></pre></li><li><p>在CMakeLists.txt添加编译选项</p><pre><code class="lang-c++">find_package(......  message_generation)

add_message_files(FILES Person.msg)
generate_messages(DEPENDENCIES std_msgs)

catkin_package(...... message_runtime)</code></pre></li><li>编译生成语言相关文件</li></ul><p>Person.msg(是在节点下创建改文件，对应本课程，就是在/catkin_ws/src/learning_topic/msg话题下创建，以此完成数据接口定义)</p><pre><code class="lang-c++">string name
uint8 sex
uint8 age

uint8 unknown = 0
uint8 male = 1
uint8 female = 2
</code></pre><h2>8.3 创建发布者代码</h2><ul><li>初始化ROS节点；</li><li>向ROS Master注册节点信息，包括发布的话题名和话题中的消息类型；</li><li>创建消息数据；</li><li>按照一定频率循环发布消息。</li></ul><pre><code class="lang-c++"># include &lt;ros/ros.h&gt;
# include &lt;learning_topic/Person.h&gt;

int main(int argc, char **argv)

{
    //ROS初始化
    ros::init(argc,argv, &quot;person_publisher&quot;);

    //创建节点句柄
    ros::NodeHandle n;

    //创建一个publisher,发布名为/person_info的topic,消息类型为learning_topic::Person, 队列长度10
    ros::Publisher person_info_pub = n.advertise&lt;lerning_topic::Person&gt;(&quot;/person_info&quot;,10);

    //设置循环频率
    ros::Rate loop_rate(1);
    int count = 0;
    while (ros::ok())
    {
        //初始化learning_topic::Person类型的消息
        learning_topic::Person person_msg;
        person_msg.name = &quot;Tom&quot;;
        person_msg.age = 18;
        person_msg.sex  = learning_topic::Person::male;

          //发布消息
        person_info_pub.publish(person_msg);
        ROS_INFO(&quot;Publish Person Info: name:%s age:%d sex:%d&quot;, person_msg.name.c_str(), person_msg.age, person_msg.sex);

        //按照循环频率延时
        loop_rate.sleep();

    }
}
</code></pre><h2>8.4 创建订阅者代码</h2><ul><li>初始化ROS节点；</li><li>订阅需要的话题；</li><li>循环等待话题消息，接收到消息后进入回调函数；</li><li><p>在回调函数中完成消息处理。</p><pre><code class="lang-c++"># include &lt;ros/ros.h&gt;
# include &quot;learning_topic/Person.h&quot;

//接收到订阅的消息后，进入消息回调函数，以及时调用处理
void personinfoCallback(const learning_topic::Person::ConstPtr&amp; msg)
{
    //将接收到的消息打印出来，以进行排查
    ROS_INFO(&quot;Subcribe Person Info: name:%s age:%d sex:%d&quot;, msg-&gt;name.c_str(), msg-&gt;age, msg-&gt;sex);
}

int main(int argc, char **argv)
{
    //初始化ROS节点
    ros::init(argc, argv, &quot;person_subscriber&quot;);

    //创建节点句柄
    ros::NodeHandle n;

    //创建一个Subscriber，订阅名为/person_info的topic，注册回调函数personInfoCallback
    ros::Subscriber person_info_sub = n.subscribe(&quot;/person_info&quot;, 10, personInfoCallback);

    //循环等待回调函数
    ros::spin();

    return 0;
}</code></pre><h2>8.5 配置代码编译规则</h2></li><li>设置需要编译的代码和生成的可执行文件；</li><li>设置链接库；</li><li><p>添加依赖库。<br>CMakeLists.txt</p><pre><code class="lang-c++">add_executable(person_publisher src/person_publisher.cpp)
target_link_libraries(person_publisher ${catkin_LIBRARIES})
add_dependencies(person_publisher ${PROJECT_NAME}_generate_messages_cpp)

add_executable(person_subscriber src/person_subscriber.cpp)
target_link_libraries(person_subscriber ${catkin_LIBRARIES})
add_dependencies(person_subscriber ${PROJECT_NAME}_generate_messages_cpp)</code></pre></li></ul><h2>8.6 编译并运行发布者和订阅者</h2><pre><code class="lang-c++">cd ~/catkin_ws
catkin_make
source devel/setup.bash
roscore
rosrun learning_topic person_subscriber
rosrun learning_topic person_publisher</code></pre><h1>9.客户端Client编程实现</h1><h2>9.1 话题模型</h2><p><img src="http://image.hantaotao.top/image/2024/ROS/1025/Pastedimage20240908124453-min.png" alt="Pastedimage20240908124453-min.png||600" title="Pastedimage20240908124453-min.png||600"></p><h2>9.2 创建功能包</h2><pre><code class="lang-c++">cd ~/catkin_ws/src
catkin_create_pkg learning_service roscpp rospy std_msgs geometry_msgs turtlesim</code></pre><h2>9.3 创建客户端代码</h2><ul><li>初始化ROS节点；</li><li>创建一个Client实例；</li><li>发布服务请求数据；</li><li>等待Service处理之后的应答结果。</li><li><p>turtle_spawn.cpp</p><pre><code class="lang-c++"># include &lt;ros/ros.h&gt;
# include &lt;turtlesim/Spawn.h&gt;

int main(int argc, char** argv)
{
    //初始化ROS节点
    ros::init(argc, argv, &quot;turtle_spawn&quot;);

    //创建节点句柄
    ros::NodeHandle node;

    //发现/spawn服务后，创建一个服务客户端，连接名为/spawn的service
    ros::service::waitForService(&quot;/spawn&quot;);
    ros::ServiceClient add_turtle = node.serviceClient&lt;turtlesim::Spawn&gt;(&quot;/Spawn&quot;);

    //初始化turtlesim::Spawn的请求数据
    turtlesim::Spawn srv;
    srv.request.x = 2.0;
    srv.request.y = 2.0;
    srv.request.name = &quot;turtle2&quot;;

    //请求服务调用
    ROS_INFO(&quot;Call service to spawn turtlesim[x:%0.6f, y:%0.6f, name:%s]&quot;, srv.request.x, srv.request.y, srv.request.name.c_str());
    add_turtle.call(srv);

    //显示服务调用结果
    ROS_INFO(&quot;Spawn turtle successfully [name:%s]&quot;, srv.response.name.c_str());

    return 0;

}</code></pre><h2>9.4 配置客户端代码编译规则</h2></li><li>设置需要编译的代码和生成的可执行文件；</li><li><p>设置链接库。<br>CmakeList.txt</p><pre><code class="lang-c++">add_executable(turtle_spawn src/turtle_spawn.cpp)
target_link_libraries(turtle_spawn ${catkin_LIBRARIES})</code></pre></li></ul><h2>9.5 编译并运行客户端</h2><pre><code class="lang-c++">cd ~/catkin_ws
catkin_make
source devel/setup.bash
roscorer
rosrun turtlesim turtlesim_node
rosrun learning_service turtle_spawn</code></pre><h1>10.服务端Server的编程实现</h1><h2>10.1 服务模型</h2><p><img src="http://image.hantaotao.top/image/2024/ROS/1025/Pastedimage20240908162131-min.png" alt="Pastedimage20240908162131-min.png||600" title="Pastedimage20240908162131-min.png||600"></p><h2>10.2 创建服务器</h2><ul><li>初始化ROS节点；</li><li>创建Service实例；</li><li>循环等待服务请求，进入回调函数；</li><li><p>在回调函数中完成服务功能的处理，并反馈应答数据。<br>turtle_command_servicer.cpp</p><pre><code class="lang-c++"># include&lt;ros/ros.h&gt;
# include&lt;geometry_msgs/Twist.h&gt;
# include&lt;std_srvs/Trigger.h&gt;

ros::Publisher turtle_vel_pub;
bool pubCommand = false;

//service回调函数，输入参数req，输出参数res
bool commandCallback(std_srvs::Trigger::Request &amp;req, std_srvs::Trigger::Response &amp;res)
{
    pubCommand = !pubCommand;

    //显示请求数据
    ROS_INFO(&quot;Publish turtle velocity command [%s]&quot;, pubCommand==true?&quot;YES&quot;:&quot;NO&quot;);

    //设置反馈数据
    res.success = true;
    res.message = &quot;Change turtle command state!&quot;;
    return true;
}

int main(int argc, char** argv)
{
    //ROS初始化
    ros::init(argc, argv, &quot;turtle_command_server&quot;);

    //创建节点句柄
    ros::NodeHandle n;

    //创建一个名为/tutle_command的server，注册回调函数commandCallback
    ros::ServiceServer command_service = n.advertiseService(&quot;/turtle_command&quot;, commandCallback);

    //创建一个Publisher，发布名为/turtle1/cmd_vel的topic，消息类型为geometry_msgs::Twist,队列长度为10
    turtle_vel_pub = n.advertise&lt;geometry_msgs::Twist&gt;(&quot;/turtle1/cmd_vel&quot;, 10);

    //循环等到回调函数
    ROS_INFO(&quot;Ready to receive turtle command.&quot;);

    //设置循环的频率
    ros::Rate loop_rate(10);

    while(ros::ok())
    {
        //查看一次回调函数队列
        ros::spinOnce();

        //如果标志为true，则发布速度指令
        if(pubCommand)
        {
            geometry_msgs::Twist vel_msg;
            vel_msg.linear.x = 0.5;
            vel_msg.angular.z = 0.2;
            turtle_vel_pub.publish(vel_msg);
        }

        //按照循环频率延时
        loop_rate.sleep();
    }

    return 0;
}</code></pre></li></ul><h2>10.3 配置服务器代码编译规则</h2><ul><li>设置需要编译的代码和生成的可执行文件；</li><li><p>设置链接库。</p><pre><code class="lang-c++">add_executable(turtle_command_server src/turtle_command_server.cpp)
target_link_libraries(turtle_command_server ${catkin_LIBRARIES})
</code></pre></li></ul><h2>10.4 编译并运行服务器</h2><pre><code class="lang-c++">cd ~/catkin_ws
catkin_make
source devel/setup.bash
roscore
rosrun turtlesim turtlesim_node
rosrun learning_service turtle_command_server
rosservice call /tuetle_command&quot;{}&quot;</code></pre><h1>11.服务数据的定义和使用</h1><h2>11.1 服务模型</h2><p><img src="http://image.hantaotao.top/image/2024/ROS/1025/Pastedimage20240908183749-min.png" alt="Pastedimage20240908183749-min.png||800" title="Pastedimage20240908183749-min.png||800"></p><h2>11.2 自定义服务数据</h2><ul><li><p>定义srv文件<br>Person.srv   （使用三个）</p><pre><code class="lang-c++">string name
uint8 age
uint8 sex

uint8 unknown = 0
uint8 male = 1
uint8 female = 2
---
string result</code></pre></li><li><p>在package.xml中添加功能包依赖</p><pre><code class="lang-c++">&lt;build_depend&gt;message_generation&lt;/build_depend&gt;
&lt;exec_depend&gt;message_runtime&lt;/exec_depend&gt;</code></pre></li><li><p>在CMakeList.txt添加编译选项</p><pre><code class="lang-c++">find_package(... message_generation)

add_service_files(FILES Person.srv)
generate_messages(DEPENDENCIES std_msgs)

catkin_package(... message_runtime)</code></pre></li><li>编译生成语言相关文件</li></ul><h2>11.3 创建服务器代码</h2><ul><li>初始化ROS节点</li><li>创建Server实例</li><li>循环等待服务请求，进入回调函数</li><li><p>在回调函数中完成服务功能的处理，并反馈应答数据。</p><pre><code class="lang-c++">/*
改例程将用于执行/show_person服务，服务数据类型learning_service::Person
*/
# include&lt;ros/ros.h&gt;
# include &quot;learning_service/Person.h&quot;

//service回调函数，输入参数req，输出参数res
bool personCallback(learning_service::Person::Request &amp;req, learning_service::Person::Response &amp;res)
{
    //显示请求数据
    ROS_INFO(&quot;Person: name:%s age:%d sex:%d&quot;, req.name.c_str(), req.age, req.sex);

    //设置反馈数据
    res.result = &quot;OK&quot;;
    return true;
}

int main(int argc, char** argv)
{
    //ROS初始化
    ros::init(argc, argv, &quot;person_server&quot;);

    //创建节点句柄
    ros::NodeHandle n;

    //创建一个名为/show_person的server，注册回调函数personCallback
    ros::ServiceServer person_service = n.advertiseService(&quot;/show_person&quot;, personCallback);

    //循环等到回调函数
    ROS_INFO(&quot;Ready to show person information.&quot;);
    ros::spin();
    return 0;
}</code></pre></li></ul><h2>11.4 创建客户端代码</h2><ul><li>初始化ROS节点</li><li>创建一个Client实例</li><li>发布服务请求数据</li><li><p>等待server处理之后的应答结果<br>person_client.cpp</p><pre><code class="lang-c++">/*
该例程将请求/show_person服务，服务数据类型learning_service::Person

*/

# include &lt;ros/ros.h&gt;
# include &quot;learning_service/Person.h&quot;

int main(int argc, char** argv)
{
    //初始化ROS节点
    ros::init(argc, argv, &quot;person_client&quot;);
    
    //创建节点句柄
    ros::NodeHandle node;

    //发现/show_person服务后，创建一个服务客户端，连接名为/show_person的service
    ros::service::waitForService(&quot;/show_person&quot;);
    ros::ServiceClient person_client = node.serviceClient&lt;learning_service::Person&gt;(&quot;/show_person&quot;);

    //初始化learning_service::Person的请求数据
    learning_service::Person srv;
    srv.request.name = &quot;Tom&quot;;
    srv.request.age = 20;
    srv.request.sex = learning_service::Person::Request::male;

    //请求服务调用
    ROS_INFO(&quot;Call service to show person[name:%s, age:%d, sex:%d]&quot;, srv.request.name.c_str(), srv.request.age, srv.request.sex);
    person_client.call(srv);
 
    //显示服务调用结果
    ROS_INFO(&quot;Show person result: %s&quot;, srv.response.result.c_str());

    return 0;
}
</code></pre></li></ul><h2>11.5 配置服务器/客户端代码编译规则</h2><ul><li>设置需要编译的代码和生成的可执行文件；</li><li>设置链接库；</li><li><p>添加依赖项。<br>CMakeLists.txt</p><pre><code class="lang-c++">add_executable(person_server src/person_server.cpp)
target_link_libraries(person_server ${catkin_LIBRARIES})
add_dependencies(person_server ${PROJECT_NAME}_gencpp)

add_executable(person_client src/person_client.cpp)
target_link_libraries(person_client ${catkin_LIBRARIES})
add_dependencies(person_client ${PROJECT_NAME}_gencpp)</code></pre></li></ul><h2>11.6 编译并运行客户端和服务端</h2><pre><code class="lang-c++">cd ~/catkin_ws
catkin_make
source devel/setup.bash
roscore
rosrun learning_service person_server
rosrun learning_service person_client</code></pre><hr><h1>12、参数的使用与编程方法</h1><h2>12.1 参数模型</h2><p><img src="http://image.hantaotao.top/image/2024/ROS/1025/Pastedimage20241006213515-min.png" alt="Pastedimage20241006213515-min.png||800" title="Pastedimage20241006213515-min.png||800"></p><h2>12.2 创建功能包</h2><pre><code class="lang-c++">cd ~/catkin_ws/src/
catkin_create_pkg learning_parameter roscpp rospy std_srvs</code></pre><h2>12.3 参数命令行使用</h2><p>rosparam</p><ul><li><p>列出当前多有参数</p><pre><code>rosparam list</code></pre></li><li><p>显示某个参数值</p><pre><code>$ rosparam get param_key</code></pre></li><li><p>设置某个参数值</p><pre><code>$ rosparam set param_key param_value</code></pre></li><li><p>保存参数到文件</p><pre><code>$ rosparam dump file_name</code></pre></li><li><p>从文件读取参数</p><pre><code>$ rosparam load file_name</code></pre></li><li><p>删除参数</p><pre><code>$ rosparam delete param_key</code></pre></li></ul><p>YAML 参数文件（以小海龟仿真器为例）</p><pre><code class="lang-c++">background_b: 255
background_g: 86
background_r: 69
rosdistro: &#039;melodic&#039;
roslaunch:
    uris:[host_hcx_vpc_43763:&#039;http://hcx-vpc:43763/&#039;}
rosversion: &#039;1.14.3&#039;
run_id: 077058de-a38b-11e9-818b-000c29d22e4d</code></pre><p>用以重新刷新</p><pre><code class="lang-c++">rosservice call /clear &quot;{}&quot;</code></pre><h2>12.4 编程方法</h2><p><strong>如何获取/设置参数</strong></p><ul><li>初始化ROS节点；</li><li>get函数获取参数；</li><li>set函数设置参数。</li></ul><p>设置/读取海归例程中的参数<br>parameter_config.cpp</p><pre><code class="lang-c++">#include &lt;string&gt;
#include &lt;ros/ros.h&gt;
#include &lt;std_srvs/Empty.h&gt;

int main(int argc, char **argv)
{
    int red, green, blue;

    //ros初始化
    ros::init(argc, argv, &quot;parameter_config&quot;);
    
    //创建节点句柄
    ros::NodeHandle node;
    
    //读取背景颜色参数
    ros::param::get(&quot;/background_r&quot;, red);
    ros::param::get(&quot;/background_g&quot;, green);
    ros::param::get(&quot;/background_b&quot;, blue);
    
    ROS_INFO(&quot;Get Background Color[%d, %d, %d]&quot;, red, green, blue);
    
    //设置背景颜色参数
    ros::param::set(&quot;/background_r&quot;, 0);
    ros::param::set(&quot;/background_g&quot;, 0);
    ros::param::set(&quot;/background_b&quot;, 0);
    
    ROS_INFO(&quot;Set Background Color[0, 0,0]&quot;);
    
    //读取背景颜色参数
    ros::param::get(&quot;/background_r&quot;, red);
    ros::param::get(&quot;/background_g&quot;, green);
    ros::param::get(&quot;/background_b&quot;, blue);
    
    ROS_INFO(&quot;Re-get Background Color[%d, %d, %d]&quot;, red, green, blue);
    
    //调用服务，刷新背景颜色
    ros::service::waitForService(&quot;/clear&quot;);
    ros::ServiceClient clear_background = node.serviceClient&lt;std_srvs::Empty&gt;(&quot;/clear&quot;);
    std_srvs::Empty srv;
    clear_background.call(srv);
    
    sleep(1);
    
    return 0;
    
}</code></pre><h2>12.5 配置代码编译规则</h2><ul><li>设置需要编译的代码和生成可执行文件；</li><li><p>设置链接库；</p><pre><code class="lang-c++">add_executable(parameter_config src/parameter_config.cpp)
target_link_libraries(parameter_config ${catkin_LIBRARIES})</code></pre></li></ul><h2>12.6 编译并运行发布者</h2><pre><code>$ cd ~/catkin_ws
$ catkin_make
$ source devel/setup.bash
$ roscore
$ rosrun turtlesim turtlesim_node
$ rosrun learning_parameter parameter_config</code></pre><h1>13.ROS中坐标系管理系统</h1><h2>13.1 机器人中的坐标变换</h2><p>通过“广播”与“监听”的方式实现的。</p><pre><code class="lang-c++">$ sudo apt-get install ros-melodic-turtle-tf
$ roslaunch turtle_tf turtle_tf_demo.launch
$ rosrun turtlesim turtle_teleop_key
$ rosrun tf view_frames</code></pre><h1>14.tf坐标系广播与监听的编程实现</h1><h2>14.1 创建功能包</h2><pre><code>$ cd ~/catkin_ws/src
$ catkin_create_pkg learning_tf roscpp rospy tf turtlesim</code></pre><h2>14.2 创建tf广播器代码</h2><ul><li>定义TF广播器（TransformBroadcaster）</li><li>创建坐标变化值</li><li>发布坐标变化（sendTransform）</li></ul><p>turtle_tf_broadcaster.cpp</p><pre><code>/*
该例程产生tf数据，并计算、发布turtle2速度指令
*/

# include &lt;ros/ros.h&gt;
# include &lt;tf/transform_broadcaster.h&gt;
# include &lt;turtlesim/Pose.h&gt;

std::string turtle_name;

void poseCallback(const turtlesim::PoseConstPtr&amp; msg)
{
    //创建tf广播器
    static tf::TransformBroadcaster br;
    
    //初始化tf数据
    tf::Transform transform;
    transform.setOrigin(tf::Vector3(msg-&gt;x, msg-&gt;y, 0.0));
    tf::Quaternion q;
    q.setRPY(0,0,msg-&gt;theta);
    transform.setRotation(q);

    //广播world与海龟坐标系之间的tf数据
    br.sendTransform(tf::StampedTransform(transform,ros::Time::now(),&quot;world&quot;,turtle_name));
}
int main(int argc,char**argv)
{
    //初始化ROS节点
    ros::init(argc,argv,&quot;my_tf_broadcaster&quot;);

    //输入参数作为海龟的名字
    if (argc  !=2)
    {
        ROS_ERROR(&quot;need turtle name as argument&quot;);
        return -1;
    }

    turtle_name = argv[1];

    //订阅海龟的位姿话题
    ros::NodeHandle node;
    ros::Subscriber sub = node.subscribe(turtle_name+&quot;/pose&quot;,10,&amp;poseCallback);
    
    //循环等到回调函数
    ros::spin();
    return 0;
};
</code></pre><h2>14.3 创建tf监听器代码</h2><p>turtle_tf_listener.cpp</p><pre><code class="lang-c++">#include &lt;ros/ros.h&gt;
#include &lt;tf/transform_listener.h&gt;
#include &lt;geometry_msgs/Twist.h&gt;
#include &lt;turtlesim/Spawn.h&gt;

int main(int argc, char** argv)
{
    //初始化ROS节点
    ros::init(argc, argv, &quot;my_tf_listener&quot;);

    //创建节点句柄
    ros::NodeHandle node;

    //请求产生turtle2
    ros::service::waitForService(&quot;/spawn&quot;);
    ros::ServiceClient add_turtle = node.serviceClient&lt;turtlesim::Spawn&gt;(&quot;/spawn&quot;);
    turtlesim::Spawn srv;
    add_turtle.call(srv);
    
    //创建发布turtle2速度控制指令的发布者
    ros::Publisher turtle_vel =  node.advertise&lt;geometry_msgs::Twist&gt;(&quot;/turtle2/cmd_vel&quot;, 10);
    
    //创建tf的监听器
    tf::TransformListener listener;

    ros::Rate rate(10.0);
    while (node.ok())
    {
        //获取turtle1与turtle2坐标系之间的tf数据
        tf::StampedTransform transform;
        try
        {
            listener.waitForTransform(&quot;/turtle2&quot;, &quot;/turtle1&quot;, ros::Time(0), ros::Duration(3.0));
            listener.lookupTransform(&quot;/turtle2&quot;, &quot;/turtle1&quot;, ros::Time(0), transform);
        }
        catch (tf::TransformException &amp; ex)
        {
            ROS_ERROR(&quot;%s&quot;, ex.what());
            ros::Duration(1.0).sleep();
            continue;
        }
            
        //根据turtle1与turtle2坐标系之间的位置关系，发布turtle2的速度控制指令
        geometry_msgs::Twist vel_msg;
        vel_msg.angular.z = 4.0 * atan2(transform.getOrigin().y(),
                                        transform.getOrigin().x());
        vel_msg.linear.x = 0.5 * sqrt(pow(transform.getOrigin().x(), 2) +
                                      pow(transform.getOrigin().y(), 2));
        turtle_vel.publish(vel_msg);

        rate.sleep();
    }
        
    return 0;
};
</code></pre><h2>14.4 配置tf广播器与监听器代码编译规则</h2><ul><li>设置需要编译的代码和生成的可执行文件；</li><li><p>设置链接库。<br>CMakeList.txt</p><pre><code>add_executable(turtle_tf_broadcaster src/turtle_tf_broadcaster.cpp)
target_link_libraries(turtle_tf_broadcaster ${catkin_LIBRARIES})

add_executable(turtle_tf_listener src/turtle_tf_listener.cpp)
target_link_libraries(turtle_tf_listener ${catkin_LIBRARIES])</code></pre><h2>14.5 编译并运行</h2><pre><code>cd ~/catkin_ws
catkin_make
source devel/setup.bash
roscore
rosrun turtlesim turtlesim_node
rosrun learning_tf turtle_tf_broadcaster__name:=turtle1_tf_broadcaster /turtlel
rosrun learning_tf turtle_tf_broadcaster__name:=turtle2_tf_broadcaster/turtle2
rosrun learning_tf turtle_tf_listener
rosrun turtlesim turtle_teleop_key</code></pre></li></ul><h1>15. launch启动文件的使用方法</h1><ul><li><p>launch文件：通过XML文件实现多节点的配置和启动</p><h2>15.1 launch文件语法</h2><pre><code>&lt;launch&gt;
  &lt;node pkg=&quot;turtlesim&quot; name=&quot;sim1&quot; type=&quot;turtlesim_node&quot;/&gt;
  &lt;node pkg=&quot;turtlesim&quot; name=&quot;sim2&quot; type=&quot;turtlesim_node&quot;/&gt;
&lt;/launch&gt;</code></pre></li><li><p>launch文件中的根元素采用<code>&lt;launch&gt;</code>标签定义<br>语法命令：</p><pre><code>启动节点   
&lt;node pkg=&quot;package-name&quot; type=&quot;executable-name&quot; name=&quot;node-name&quot;/&gt;

pkg:节点所在功能包名称
type:节点的可执行文件名称
name:节点运行时的名称

此外还有其它属性：output respawn required ns args</code></pre></li></ul><p>参数设置</p><ul><li><p><code>&lt;param&gt;</code> 设置ROS系统运行中的参数，存储在参数服务器中</p><pre><code>&lt;param name=&quot;output_frame&quot; value=&quot;odom&quot;/&gt;

name:参数名
value：参数值</code></pre></li><li><p><code> &lt;rosparam&gt;</code>  加载参数文件中的多个参数：</p><pre><code>&lt;rosparam file= &quot;params.yaml&quot; command=&quot;load&quot; ns=&quot;params&quot;/&gt;</code></pre></li><li><p><code>&lt;arg&gt;</code> launch文件内部的局部变量，仅限于launch文件使用</p><pre><code>&lt;arg name=&quot;arg-name&quot; default=&quot;arg-value&quot;/&gt;

name:参数名
value:参数值

调用
&lt;param name=&quot;foo&quot; value=&quot;$(arg arg-name)&quot;/&gt;
&lt;node name=&quot;node&quot; pkg=&quot;package&quot; type=&quot;type&quot; args=&quot;$(arg arg-name)&quot;/&gt;</code></pre></li><li><p><code>&lt;remap&gt;</code> 重映射 重映射ROS计算资源的命名</p><pre><code>&lt;remap from=&quot;/turtlebot/cmd_vel&quot; to=&quot;/cmd_vel&quot;/&gt;

from:重命名
to:映射之后的命名</code></pre></li><li><p><code>&lt;include&gt;</code> 嵌套 包含其它launch文件，类似C语言中的头文件包含</p><pre><code>&lt;include file=&quot;$(dirname)/other.launch&quot;/&gt;

file:包含的其它launch文件路径</code></pre><h2>15.2 运行相关</h2></li><li><p>创建功能包</p><pre><code>catkin_create_pkg learning_launch</code></pre></li><li>可以创建一个文件夹，例如命名为<code>launch</code>来存放launch文件，之后<code>catkin_make</code>来进行编译。</li><li><p>编译完成之后，进行启动</p><pre><code>roslaunch xxx(功能包名字) xxx(launch文件)

e.g. 
roslaunch learning_launch simple.launch</code></pre><hr><h1>问题发现与解决</h1><h2>1.解决每次打开ubuntu软件商店程序出现Unable to download updates from extensions.gnome.org</h2><pre><code>sudo add-apt-repository ppa:gnome-shell-extensions/ppa
sudo apt-get update
sudo apt-get install gnome-shell-extensions</code></pre></li></ul>
]]></content:encoded>
<slash:comments>3</slash:comments>
<comments>https://blog.hantaotao.top/archives/136/#comments</comments>
<wfw:commentRss>https://blog.hantaotao.top/feed/tag/ROS/archives/136/</wfw:commentRss>
</item>
</channel>
</rss>