ROS源代码阅读(1)

这篇博客详细介绍了ROS工作空间的创建步骤,并深入解析了ROS的main入口函数和命令行参数处理。通过示例代码展示了如何编写ROS服务客户端,并解释了`ros::init()`函数在程序启动中的作用,以及命令行参数如`rosrun`中的`:=`如何被处理。同时,文章还介绍了ROS中数据类型定义和源码中关键函数的用途。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ros工作空间创建教程 

http://wiki.ros.org/kinetic/Installation/Source

1、首先ros源码获取可以通过github获取:

https://github.com/ros/ros_comm

​
git clone https://github.com/ros/ros_comm.git

​

3、main入口函数

我们知道一个程序入口 都是从main开始的,那么我们就拿维基中ros的一个例程来讲

 源码地址:

http://wiki.ros.org/ROS/Tutorials/WritingServiceClient%28c%2B%2B%29

   1 #include "ros/ros.h"
   2 #include "beginner_tutorials/AddTwoInts.h"
   3 
   4 bool add(beginner_tutorials::AddTwoInts::Request  &req,
   5          beginner_tutorials::AddTwoInts::Response &res)
   6 {
   7   res.sum = req.a + req.b;
   8   ROS_INFO("request: x=%ld, y=%ld", (long int)req.a, (long int)req.b);
   9   ROS_INFO("sending back response: [%ld]", (long int)res.sum);
  10   return true;
  11 }
  12 
  13 int main(int argc, char **argv)
  14 {
  15   ros::init(argc, argv, "add_two_ints_server");
  16   ros::NodeHandle n;
  17 
  18   ros::ServiceServer service = n.advertiseService("add_two_ints", add);
  19   ROS_INFO("Ready to add two ints.");
  20   ros::spin();
  21 
  22   return 0;
  23 }

main进来就调用了ros::init(argc, argv, "add_two_ints_server");,这个就是可以去ros源码

ros_comm/clients /roscpp/src/init.cpp 中找到入口函数 

void init(int& argc, char** argv, const std::string& name, uint32_t options)

如果你看别人写程序也基本都有ros::init(argc, argv, "add_two_ints_server");基本上可以确认这个就是入函数

4、命令行传参

我们在去维基查看ros的命令行使用:


http://wiki.ros.org/ROS/Tutorials/UnderstandingNodes

rosrun turtlesim turtlesim_node __name:=my_turtle

这个使用方法有:=,这个就对应到函数init(int& argc, char** argv, const std::string& name, uint32_t options)中里面的下面的源代码,查找到:=并把:=两边的字符串存在remappings中

for (int i = 0; i < argc; )
  {
    std::string arg = argv[i];
    size_t pos = arg.find(":=");
    if (pos != std::string::npos)
    {
      std::string local_name = arg.substr(0, pos);
      std::string external_name = arg.substr(pos + 2);

      ROSCPP_LOG_DEBUG("remap: %s => %s", local_name.c_str(), external_name.c_str());
      remappings[local_name] = external_name;

      // shuffle everybody down and stuff this guy at the end of argv
      char *tmp = argv[i];
      for (int j = i; j < full_argc - 1; j++)
        argv[j] = argv[j+1];
      argv[argc-1] = tmp;
      argc--;
    }
    else
    {
      i++; // move on, since we didn't shuffle anybody here to replace it
    }
  }

ros源码注释


//入口函数
void init(int& argc, char** argv, const std::string& name, uint32_t options)
{
  //追踪M_string可以看到定义typedef std::map<std::string, std::string> M_string;
  M_string remappings;

  int full_argc = argc;
  // now, move the remapping argv's to the end, and decrement argc as needed
  //将程序运行传入参数转换为remapping
  for (int i = 0; i < argc; )
  {
    std::string arg = argv[i];
    size_t pos = arg.find(":=");
    if (pos != std::string::npos)
    {
      std::string local_name = arg.substr(0, pos);
      std::string external_name = arg.substr(pos + 2);

      ROSCPP_LOG_DEBUG("remap: %s => %s", local_name.c_str(), external_name.c_str());
      remappings[local_name] = external_name;

      // shuffle everybody down and stuff this guy at the end of argv
      char *tmp = argv[i];
      for (int j = i; j < full_argc - 1; j++)
        argv[j] = argv[j+1];
      argv[argc-1] = tmp;
      argc--;
    }
    else
    {
      i++; // move on, since we didn't shuffle anybody here to replace it
    }
  }

  //将程序运行传入参数转换为remapping后调用另一个init函数
  init(remappings, name, options);
}

//转换传入参数为remapping后调用调用此函数
void init(const M_string& remappings, const std::string& name, uint32_t options)
{
  if (!g_atexit_registered)
  {
    g_atexit_registered = true;
//atexit函数是一个特殊的函数,它是在正常程序退出时调用的函数,我们把他叫为登记函数,
// 一个进程可以登记32个函数,这些函数由exit自动调用,这些函数被称为终止处理函数,
//atexit函数可以登记这些函数。exit调用终止处理函数的顺序和atexit登记的顺序相反,
//如果一个函数被多次登记,也会被多次调用,也就是说退出时将调用atexitCallback这个函数。
    atexit(atexitCallback);
  }

  if (!g_global_queue)
  {
    g_global_queue.reset(new CallbackQueue);
  }

  if (!g_initialized)
  {
    g_init_options = options;
    g_ok = true;

    ROSCONSOLE_AUTOINIT;
    // Disable SIGPIPE
#ifndef WIN32
    signal(SIGPIPE, SIG_IGN);
#endif
    check_ipv6_environment();
    //network相关的初始化
    network::init(remappings);
    //master相关的初始化
    master::init(remappings);
    // names:: namespace is initialized by this_node
    this_node::init(name, remappings, options);
    file_log::init(remappings);
    param::init(remappings);

    g_initialized = true;
  }
}

ros几种数据定义:

roscpp_core/cpp_common/include/ros/datatypes.h

typedef std::vector<std::pair<std::string, std::string> > VP_string;
typedef std::vector<std::string> V_string;
typedef std::set<std::string> S_string;
typedef std::map<std::string, std::string> M_string;
typedef std::pair<std::string, std::string> StringPair;

参考自:

ROS源代码阅读(1):找切入点_正心公子的博客-CSDN博客https://blog.csdn.net/wanghuiquan0712/article/details/78010697

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值