# 【ROS教程】ROS常用API讲解

@[TOC](https://github.com/UnderTurrets/notes/blob/master/ROS/%E6%96%87%E7%AB%A0%E7%9B%AE%E5%BD%95/README.md)

***

## 1.节点初始化

```cpp
ROSCPP_DECL void init(int &argc, char **argv, const std::string& name, uint32_t options = 0);
ROSCPP_DECL void init(const M_string& remappings, const std::string& name, uint32_t options = 0);
ROSCPP_DECL void init(const VP_string& remapping_args, const std::string& name, uint32_t options = 0);
```

* 这里讲解第一种初始化方式

| 参数   | 含义               |
| ---- | ---------------- |
| argc | main函数的第一个参数     |
| argv | main函数的第二个参数     |
| name | 节点的名字，**必须是唯一的** |

## 2.话题通信

### 2.1 创建发布者对象

```cpp
template <class M>
Publisher NodeHandle::advertise(const std::string& topic, uint32_t queue_size, bool latch = false);
  
template <class M>
Publisher NodeHandle::advertise(const std::string& topic, uint32_t queue_size,
                        const SubscriberStatusCallback& connect_cb,
                        const SubscriberStatusCallback& disconnect_cb = SubscriberStatusCallback(),
                        const VoidConstPtr& tracked_object = VoidConstPtr(),
                        bool latch = false);
```

* 这里讲解第一种构造方式

| 参数          | 含义                                                |
| ----------- | ------------------------------------------------- |
| topic       | 话题的名字，**必须是唯一的**                                  |
| queue\_size | 等待发送给订阅者的最大消息数量                                   |
| latch       | 如果为 true,该话题发布的最后一条消息将被保存，并且后期当有订阅者连接时会将该消息发送给订阅者 |

### 2.2 消息发布

```cpp
template <typename M>
      void Publisher::publish(const M& message) const;
```

| 参数      | 含义     |
| ------- | ------ |
| message | 被组织的消息 |

### 2.3 创建订阅者对象

```cpp
template<class M>
Subscriber NodeHandle::subscribe(const std::string& topic, uint32_t queue_size, void(*fp)(const boost::shared_ptr<M const>&), const TransportHints& transport_hints = TransportHints());

template<class M>
Subscriber NodeHandle::subscribe(const std::string& topic, uint32_t queue_size, const boost::function<void (const boost::shared_ptr<M const>&)>& callback,
                         const VoidConstPtr& tracked_object = VoidConstPtr(), const TransportHints& transport_hints = TransportHints());
```

| 参数          | 含义                        |
| ----------- | ------------------------- |
| topic       | 话题的名字，**必须是唯一的**          |
| queue\_size | main函数的第二个参数              |
| fp          | 回调函数的函数指针                 |
| return      | 调用成功时，返回一个订阅者对象，失败时，返回空对象 |

## 3.服务通信

### 3.1 创建服务对象

```cpp
  template<class T, class MReq, class MRes>
  ServiceServer NodeHandle::advertiseService(const std::string& service, bool(T::*srv_func)(MReq &, MRes &), T *obj);
  
  template<class T, class MReq, class MRes>
  ServiceServer NodeHandle::advertiseService(const std::string& service, bool(T::*srv_func)(ServiceEvent<MReq, MRes>&), T *obj);

  template<class T, class MReq, class MRes>
  ServiceServer NodeHandle::advertiseService(const std::string& service, bool(T::*srv_func)(MReq &, MRes &), const boost::shared_ptr<T>& obj);

  template<class T, class MReq, class MRes>
  ServiceServer NodeHandle::advertiseService(const std::string& service, bool(T::*srv_func)(ServiceEvent<MReq, MRes>&), const boost::shared_ptr<T>& obj);

  template<class MReq, class MRes>
  ServiceServer NodeHandle::advertiseService(const std::string& service, bool(*srv_func)(MReq&, MRes&));

  template<class MReq, class MRes>
  ServiceServer NodeHandle::advertiseService(const std::string& service, bool(*srv_func)(ServiceEvent<MReq, MRes>&));
  
  template<class MReq, class MRes>
  ServiceServer NodeHandle::advertiseService(const std::string& service, const boost::function<bool(MReq&, MRes&)>& callback, 
                                 const VoidConstPtr& tracked_object = VoidConstPtr());

  template<class S>
  ServiceServer NodeHandle::advertiseService(const std::string& service, const boost::function<bool(S&)>& callback, 
                                 const VoidConstPtr& tracked_object = VoidConstPtr());
```

| 参数        | 含义                  |
| --------- | ------------------- |
| service   | 服务名称，**必须是唯一的**     |
| srv\_func | 接收到请求时，需要处理请求的回调函数  |
| return    | 请求成功时返回服务对象，否则返回空对象 |

### 3.2 创建客户对象

```cpp
  template<class MReq, class MRes>
  ServiceClient NodeHandle::serviceClient(const std::string& service_name, bool persistent = false, 
                              const M_string& header_values = M_string());
  template<class Service>
  ServiceClient NodeHandle::serviceClient(const std::string& service_name, bool persistent = false, 
                              const M_string& header_values = M_string());
                            
```

| 参数            | 含义              |
| ------------- | --------------- |
| service\_name | 服务名称，**必须是唯一的** |

### 3.3 客户发送请求

```cpp
  template<class Service>
  bool ServiceClient::call(Service& service);
```

| 参数      | 含义            |
| ------- | ------------- |
| service | .srv文件定义的服务类型 |

### 3.4 客户对象等待服务

```cpp
ROSCPP_DECL bool service::waitForService(const std::string& service_name, int32_t timeout);
ROSCPP_DECL bool service::waitForService(const std::string& service_name, ros::Duration timeout = ros::Duration(-1));
```

| 参数            | 含义                         |
| ------------- | -------------------------- |
| service\_name | 被等待的服务名称，**必须是唯一的**        |
| timeout       | 等待最大时常，默认为 -1，可以永久等待直至节点关闭 |
| return        | 成功返回 true，否则返回 false       |

## 4. 回旋函数

* 简而言之，**用到回调函数，就要用回旋函数处理**

### 4.1 spin

```cpp
/** 
 * \brief 进入循环处理回调 
 */
ROSCPP_DECL void spin();
```

### 4.2 spinOnce

```cpp
/**
 * \brief 处理一轮回调
 *
 * 一般应用场景:
 *     在循环体内，处理所有可用的回调函数
 * 
 */
ROSCPP_DECL void spinOnce();
```

## 5.时间

### 5.1 时刻

#### 5.1.1 获取当前时刻

```cpp
ros::init(argc,argv,"hello_time");
ros::NodeHandle nh;//必须创建句柄，否则时间没有初始化，导致后续API调用失败
ros::Time right_now = ros::Time::now();//将当前时刻封装成对象
ROS_INFO("当前时刻:%.2f",right_now.toSec());//获取距离 1970年01月01日 00:00:00 的秒数
ROS_INFO("当前时刻:%d",right_now.sec);//获取距离 1970年01月01日 00:00:00 的秒数
```

#### 5.1.2 设置时刻

```cpp
ros::init(argc,argv,"hello_time");
ros::NodeHandle nh;//必须创建句柄，否则时间没有初始化，导致后续API调用失败
ros::Time someTime(100,100000000);// 参数1:秒数  参数2:纳秒
ROS_INFO("时刻:%.2f",someTime.toSec()); //100.10
ros::Time someTime2(100.3);//直接传入 double 类型的秒数
ROS_INFO("时刻:%.2f",someTime2.toSec()); //100.30
```

### 5.2 时间间隔

#### 5.2.1 设置时间间隔

```cpp
ros::init(argc,argv,"hello_time");
ros::NodeHandle nh;//必须创建句柄，否则时间没有初始化，导致后续API调用失败
ros::Duration du(10);//持续10秒钟,参数是double类型的，以秒为单位
ROS_INFO("持续时间:%.2f",du.toSec());//将持续时间换算成秒
```

#### 5.2.2 进行休眠

```cpp
ros::init(argc,argv,"hello_time");
ros::NodeHandle nh;//必须创建句柄，否则时间没有初始化，导致后续API调用失败
ros::Duration du(10);//持续10秒钟,参数是double类型的，以秒为单位
du.sleep();//按照指定的持续时间休眠
```

### 5.3 设置运行频率

```cpp
Rate::Rate(double frequency);
```

| 参数        | 含义   |
| --------- | ---- |
| frequency | 运行频率 |

## 6.参数设置

### 6.1 修改或新增参数

```cpp
  void NodeHandle::setParam(const std::string& key, const XmlRpc::XmlRpcValue& v) const;
  void NodeHandle::setParam(const std::string& key, const std::string& s) const;
  void NodeHandle::setParam(const std::string& key, const char* s) const;
  void NodeHandle::setParam(const std::string& key, double d) const;
  void NodeHandle::setParam(const std::string& key, int i) const;
  void NodeHandle::setParam(const std::string& key, bool b) const;
  void NodeHandle::setParam(const std::string& key, const std::vector<std::string>& vec) const;
  void NodeHandle::setParam(const std::string& key, const std::vector<double>& vec) const;
  void NodeHandle::setParam(const std::string& key, const std::vector<float>& vec) const;
  void NodeHandle::setParam(const std::string& key, const std::vector<int>& vec) const;
  void NodeHandle::setParam(const std::string& key, const std::vector<bool>& vec) const;
  void NodeHandle::setParam(const std::string& key, const std::map<std::string, std::string>& map) const;
  void NodeHandle::setParam(const std::string& key, const std::map<std::string, double>& map) const;
  void NodeHandle::setParam(const std::string& key, const std::map<std::string, float>& map) const;
  void NodeHandle::setParam(const std::string& key, const std::map<std::string, int>& map) const;
  void NodeHandle::setParam(const std::string& key, const std::map<std::string, bool>& map) const;
```

* ROS提供了16种可以设置的参数类型，如上。
* 使用 `ros::param::set`有完全相同的效果

### 6.2 获取参数

```cpp
/*
    参数服务器操作之查询_C++实现:
    在 roscpp 中提供了两套 API 实现参数操作
  
    ros::NodeHandle::param(键,默认值) 
            存在，返回对应结果，否则返回默认值

    ros::NodeHandle::getParam(键,存储结果的变量)
            存在,返回 true,且将值赋值给参数2
            若果键不存在，那么返回值为 false，且不为参数2赋值

    ros::NodeHandle::getParamCached(键,存储结果的变量)--提高变量获取效率
            存在,返回 true,且将值赋值给参数2
            若果键不存在，那么返回值为 false，且不为参数2赋值

    ros::NodeHandle::getParamNames(std::vector<std::string>)
            获取所有的键,并存储在参数 vector 中 

    ros::NodeHandle::hasParam(键)
            是否包含某个键，存在返回 true，否则返回 false

    ros::NodeHandle::searchParam(参数1，参数2)
            搜索键，参数1是被搜索的键，参数2存储搜索结果的变量

    ros::param ----- 与 NodeHandle 类似
*/
```

### 6.3 删除参数

```cpp
/* 
    参数服务器操作之删除_C++实现:

    ros::NodeHandle::deleteParam("键")
        根据键删除参数，删除成功，返回 true，否则(参数不存在)，返回 false

    ros::param::del("键")
        根据键删除参数，删除成功，返回 true，否则(参数不存在)，返回 false
*/
```
