Ros2学习梳理_汇总(赵虚左老师)

Ros2_通信机制

一、通信模型

1、话题通信
2、服务通信
3、动作通信
4、参数服务

二、话题通信

1、话题通信核心实现

1-1 、C++实现

发布方

1-1.创建发布方;

publisher_ = this->create_publisher<std_msgs::msg::String>("topic", 10);
API:(创建发布方对象)

create_publisher ()
/*
模板: std_msgs::msg::String(被发布的消息类型 )
参数:
1、话题名称
2、Qos(消息队列长度)
返回值:
发布对象指针(rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_😉
*/

1-2.创建定时器;

timer_ = this->create_wall_timer(500ms, std::bind(&MinimalPublisher::timer_callback, this));
API: 创建定时器

create_wall_timer ()
/*
参数:
1、时间间隔(此处可以使用using namespace std::chrono_literals)
2、CallBack(回调函数)
返回值:
定时器对象指针(rclcpp::TimeBase::SharedPtr timer_)
*/

1-3.组织消息并发布。

publisher_->publish(message);
API:发布消息

publish()
/*
参数:
1、发布的消息
*/

订阅者

1-1.创建订阅方;

subscription_ = this->create_subscription<std_msgs::msg::String>("topic", 10, std::bind(&MinimalSubscriber::topic_callback, this, _1));
API:(创建订阅者)

create_subscription()
/*
模板:std_msgs::msg::String (消息类型)
参数:
1、话题名称
2、Qos(消息队列长度)
3、CallBack(回调函数(对订阅的消息进行处理))
返回值:订阅对象指针( rclcpp::Subscription<std_msgs::msg::String>::SharedPtr subscription_;)
*/

1-2.处理订阅到的消息。

回调函数(void topic_callback(const std_msgs::msg::String & msg))

1-2、Python实现

发布方

1.创建发布方

self.publisher_ = rclpy.create_publiser(String, 'topic', 10)
API: (创建发布方)

create_publisher()
/*
参数:
1、消息类型
2、话题名称
3、Qos(消息队列长度)
返回值:self.publisher_ (发布对象)
*/

2.创建定时器;

self.timer = self.create_timer(timer_period, self.timer_callback)
API: (创建定时器)

create_timer ()
/*
参数:
1、时间间隔
2、回调函数(处理订阅到的消息)
*/

3.组织消息并发布。

API:回调函数(self.publisher_.publish(message)

publish()
/*
参数:
1、订阅到的消息
*/

订阅者

1.创建订阅方;

self.subscription = self.create_subscription(String,'topic',self.listener_callback,10)
API:(创建订阅者)

create_subscripition ()
/*
参数:
1、消息类型
2、话题名称
3、CallBack(回调函数)
4、Qos(消息队列长度)
返回值:self.subscripition(订阅对象)
*/

2.处理订阅到的消息。

listener_callbak(self,msg)
/*
处理订阅到的消息
*/

1-3、自定义消息

1、新建msg文件夹
2、配置package.xml文件

编译依赖
<build_depend>rosidl_default_generators</build_depend>
执行依赖
<exec_depend>rosidl_default_runtime</exec_depend>
声明当前包所属的功能包组
<member_of_group>rosidl_interface_packages</member_of_group>

3、配置CMakeLists.txt文件

find_package(rosidl_default_generators REQUIRED)
为接口文件生成源码
rosidl_generate_interfaces(${PROJECT_NAME}
“msg/Student.msg”
)

C++文件包含自定义消息头文件时需要配置Vscode中俄c__cpp_properties.json文件,在文件中的includePath属性下添加一行:

“{workspaceFolder}/install/base_interfaces_demo/include/**”

三、服务通信

1、服务通信核心实现

适用于对实时性有要求,具有一定逻辑处理的应用场景中

1-1、C++服务端

1.包含头文件

#incldue “rclcpp/rclcpp.hpp”
#include “服务接口消息.hpp”

Tips:

using和using namespace的区别:
using用于引入某个命名空间中的特定名称,而using namespace则是用于引入整个命名空间的内容。

2.创建服务端

server = this->create_service<AddInts>("add_ints",std::bind(&MinimalService::add, this, _1, _2));
API:创建服务端

create_service()
/*
模板:服务接口类型
参数:
1、服务话题
2、回调函数
返回值:服务对象指针( rclcpp::Service::SharedPtr server;)
*/

3.处理请求数据并响应结果

void add(const AddInts::Request::SharedPtr req,const AddInts::Response::SharedPtr res)
回调函数中有两个内置参数,一个是AddInts::Request,一个是AddInts::Response。
*/
Tips:
可以使用命令测试服务端:
ros2 service call 服务话题(/add_ints) 声明提交数据的类型(base_interfaces_demo/srv/AddInts) 提交的数据(“{‘num1’:10,‘num2’:30}”)

1-2、C++客户端

1.包含头文件;

#include “rclcpp/rclcpp.hpp”
#include “base_interfaces_demo/srv/add_ints.hpp”

2、定义节点类

2-1.创建客户端;
rclcpp::Client<AddInts>::SharedPtr client;
client = this->create_client<AddInts>("add_ints");
API:创建客户端

create_client<服务接口>(服务话题名称)
/*
模板:服务接口消息类型
参数:服务话题名称
返回值:客户端对象指针
*/

2-2.等待服务连接;(对于服务通信而言,如果客户端连接不到服务器,那么不能发送请求
API:等待服务器连接

wait_for_service(1s)
/*
参数:
1、等待时间
*/

2-3.组织请求数据并发送;
rclcpp::Client::FutureAndRequest send_request(int_32 num1,int_32 num2)
{
auto request = std::make_shared<AddInts::Request>();
request.num1 = num1;
request.num2 = num2;
return client->async_send_request(request);
}
API:异步发送数据

async_send_request()
/*
参数:
1、消息变量request
/*

3.创建对象指针调用其功能,并处理响应;

此时不需要使用spin函数(服务通信机制是一问一答的,当响应请求后,客户端不需要一直挂起,所以这里直接创建一个客户端对象即可
auto client = std::make_shared<类名>();
3-1.需要调用连接服务的函数,然后根据链接结果做下一步处理
bool flag = client->connect_server()
3-2.连接服务后,调用请求提交函数并处理响应结果
auto future->send_request(atoi(argv[1]),atoi(argv[2]));
3-3.处理响应
rclcpp::spin_until_future_complete(client,response) == rclcpp::FutureReturnCode::SUCCESS
判断future的一个状态码
/*
参数:
1、当前节点指针
2、future指针
*/

Python服务端核心实现
“”"
1.导包;
2.初始化 ROS2 客户端;
3.定义节点类;
3-1.创建服务端;
3-2.处理请求数据并响应结果。
4.调用spin函数,并传入节点对象;
5.释放资源。

“”"
** 1.导包**

import rclpy
from rclpy.node import Node
from base_interfaces_demo.srv import AddInts

3.定义节点类

3-1.创建服务端

self.srv = self.create_service(AddInts, 'add_ints', self.add_two_ints_callback)

API:创建服务端
create_service()
/*
参数:
1、服务接口消息类型
2、服务话题名称
3、回调函数
*/
3-2.处理请求数据并响应结果
回调函数
def add(self,request,response}
该函数主要用于处理请求并产生响应

Python客户端核心实现
“”
1.导包;
2.初始化 ROS2 客户端;
3.定义节点类;
3-1.创建客户端;
3-2.等待服务连接;
3-3.组织请求数据并发送;
4.创建对象调用其功能,处理响应结果;
5.释放资源。
“”
1、导包

import sys
import rclpy
from rclpy.node import Node
from base_interfaces_demo.srv import AddInts
from rcpy.logging import get_logger//日志

3.定义节点类

3-1.创建客户端
self.client = self.create_client(AddInts,"add_ints")
API:创建客户端
create_client()
/*
参数:
1、服务接口类型
2、服务话题名称
*/
3-2.等待服务连接
self.client.wait_for_service(timeout_sec=1.0)
API:等待服务连接
wait_for_service()

/*
参数:
1、等待超时时间
/
3-3.组织请求数据并发送
自定义异步发送服务请求函数
def send_request(self):
self.req = AddInts.Request()
self.req.num1 = int(sys.argv[1])
self.req.num2 = int(sys.argv[2])
self.future = self.cli.call_async(self.req)
API:异步发送服务请求
call_async()
/

参数:
1、服务请求对象 req

*/

4.创建对象调用其功能,处理响应结果

4-1.发送请求

client = AddIntsClient()
clent.send_request()

4-2.处理响应

rclpy.spin_until_future_complete(minimal_client,minimal_client.future)
API:等待异步操作完成
spin_until_future_cmplete(client,future)
/*
参数:
1、当前客户端对象
2、future 异步操作的结果
*/

rclpy.spin_until_future_complete(minimal_client,minimal_client.future)
try:
	response = minimal_client.future.result()//返回响应对象
except Exception as e:
	 minimal_client.get_logger().info('服务请求失败:%r' % (e,) 
else:
 	minimal_client.get_logger().info( '响应结果:%d + %d = %d' %
   (minimal_client.req.num1, minimal_client.req.num2, response.sum)        

四、动作通信

动作通信适用于长时间运行任务,结构上由目标反馈结果三部分构成。目标发送和结果获取都是对服务通信的封装,连续反馈是对话题通信的封装。

1、自定义动作通信接口消息

1-1.编辑配置文件

package.xml:

action构建工具依赖

<buildtool_depend>rosidl_default_generators</buildtool_depend>

这个是<build_depend>、<exec_depend>、<export_depend>三者的集成

<depend>action_msgs</depend>

声明当前包所属的功能包组

<member_of_group>rosidl_interface_packages</member_of_group>

CMakeList.txt:

find_package(rosidl_default_generators REQUIRED)
rosidl_generate_interfaces(${PROJECT_NAME}"action/Progress.action")

2、动作通信服务端C++核心实现
/*

1.包含头文件;
2.初始化 ROS2 客户端;
3.定义节点类;
3-1.创建动作服务端;
3-2.处理提交的目标值(回调函数);
3-3.生成连续反馈与最终响应(回调函数);
3-4.处理取消任务请求(回调函数)。
4.调用spin函数,并传入节点对象指针;
5.释放资源。

*/
1、包含头文件

#include "rclcpp/rclcpp.hpp"
#include "rclcpp_action/rclcpp_action.hpp"//动作通信需要用到的头文件
#include "base_interfaces_demo/action/progress.hpp"//消息类型头文件

3、定义节点类

3-1.创建动作服务端

rclcpp_action::create_server<Progress>(
this,
"get_sum",
std::bind(&ActionServer::handle_goal,this,_1,_2),
std::bind(&ActionServer::handle_cancel,this,_1),
std::bind(&ActionServer::handle_accepted,this,_1)
);

API:创建动作服务端
create_server()
/*
模板:动作服务接口消息类型
参数:
1、当前节点
2、动作服务话题名称
3、提交目标处理函数 (回调函数)
4、取消任务请求处理函数(回调函数)
5、生成连续反馈处理函数(回调函数)
返回值:
动作消息接口类型的指针对象
*/
3-2.处理提交的目标值

 rclcpp_action::GoalResponse handle_goal(const rclcpp_action::GoalUUID & uuid,std::shared_ptr<const Progress::Goal> goal)

参数:
1、rclcpp_action::GoalUUID :一个全局唯一标识符(UUID),用于标识特定的目标请求。这可以用于在需要时查找或识别目标。
2、Progress::Goal类型的智能指针 :一个指向目标请求的共享指针
返回值类型:rclcpp_action::GoalResponse类型
Tips:
1、没有用到的成员变量可以用void()描述,例:void(uuid)
2、一般在rclcpp_action::GoalResponse下存在三个选项:

rclcpp_action::GoalResponse::ACCEPT_AND_EXECUTE
rclcpp_action::GoalResponse::ACCEPT_AND_DEFER
rclcpp_action::GoalResponse::REJECT

3-3.处理取消任务请求的函数

  rclcpp_action::CancelResponse handle_cancel(const std::shared_ptr<rclcpp_action::ServerGoalHandle<Progress>> goal_handle)

参数:
1、const std::shared_ptr<ServerGoalHandle> :表示指向ServerGoalHandle对象的共享指针
返回值:rclcpp_action::CancelResponse

Tips:
1、一般在rclcpp_action::CancelResponse下存在两个选项:

rclcpp_action::CancelResponse::ACCEPT
rclcpp_action::CanceResponse::REJECT

3-4.生成连续反馈与最终响应

std::thread(std::bind(&ActionServer::execute,this,goal_handle)).detach()

一般处理主逻辑都比较耗时,所以此处用到了子线程
std::thread(执行体).detach()-------匿名线程
回调函数execute实现:

3-4-1.初始化goal、feedback、result

//从handle_goal上获取目标信息
const auto goal = goal_handle->get_goal();
//创建一个进度反馈信息的共享指针
auto feedback = std::make_shared<Progress::Feedback>();
//创建一个结果信息的共享指针
auto result = std::make_shared<Progress::Result>();

3-4-1.生成连续反馈返回给客户端

feedback->progress = (double_t)i / goal->num;
goal_handle->publish_feedback(feedback)

3-4-2.生成最终响应结果

result->sum = sum;
goal_andle->succeed(result);

API(扩展):
1、goal_handle->get_goal();获取目标值
2、rclcpp::Rate rate(1.0);rate.sleep();设置休眠时间
3、goal_handle->is_canceling();判断是否正在取消请求
4、goal_handle->canceled();通知任务被取消并传递结果对象

3.动作通信客户端C++核心实现

/*
1.包含头文件;
2.初始化 ROS2 客户端;
3.定义节点类;
3-1.创建动作客户端;
3-2.发送请求;
3-3.处理目标发送后的反馈(回调函数);
3-4.处理连续反馈(回调函数);
3-5.处理最终响应(回调函数)。
4.调用spin函数,并传入节点对象指针;
5.释放资源。
*/
1.包含头文件

#include "rclcpp/rclcpp.hpp" 
#include "rclcpp_ation/rclcpp.hpp"
#include "base_interfaces_demo/action/progress.hpp"

3.定义节点类

3-1.创建动作客户端

rclcpp_action::Client<Progress>::SharedPtr client_ptr_;
this->client_ptr_ = rclcpp_action::create_client<Progress>(this,"get_sum");

API:创建动作客户端
create_client()
/*
模板:动作通信接口
参数:
1、当前节点对象
2、动作通信话题名称
返回值:动作通信客户端对象指针
*/
3-2.发送请求
主函数调用成员函数send_goal。
send_goal实现:

3-2-1.连接服务器

this->clent_ptr_->wait_for_action_server(std::chrono::seconds(10))

API:等待服务器连接
wait_for_action_server()
/*
参数:
1、超时时间
返回值:bool值,连接成功返回True,失败则返回False。
*/
3-2-2.发送具体请求

//设置goal_msg
auto goal_msg = Progress::Goal();
goal_msg.num = num;//提交目标值
//设置options
rclcpp_action::Client<Progress>::SendGoalOptions options;
options.goal_response_callback =std::bind(&MinimalActionClient::goal_response_callback, this, _1);
options.feedback_callback =std::bind(&MinimalActionClient::feedback_callback, this, _1, _2);
options.result_callback =std::bind(&MinimalActionClient::result_callback, this, _1);
//发送异步请求
client_->async_send_goal(goal_msg,options),

API:异步发送请求
asyn_send_goal(参数1,参数2)
/*
参数:
1、const base_interfaces-demo::action::Progress::Goal &goal;自定义的动作接口消息类型下的目标
2、const rclcpp_action::Client<base_interfaes_demo::action::Progress>::SendGoalOptions &options;发送目标选项,设置需要处理的回调函数(1、处理目标值的服务响应2、处理连续反馈3、处理最终响应)
*/

1.处理目标发送后的反馈(回调函数)
/*
参数:
1、指向ClientGoalHandle类型的实例的智能指针,它管理目标的生命周期,并提供接口来查询目标状态、取消目标、获取结果等。
*/

void goal_response_callback(rclcpp::action::ClientGoaHandle<Progress>::SharedPtr goal_handle)
{
//客户端首先发送一个目标值给服务端,服务端进行判断看目标值是否可以被接受,然后响应给客户端,如果可处理的话,goal_handle里面是由内容的,如果不可处理的话,goal_handle是个空指针。
if(!goal_handle)//goal_handle如果是个空指针
//目标请求被服务端拒绝,否则被接受
}

2.处理连续反馈(回调函数)
/*
参数:
1、这是个智能指针,用于管理特定目标(goal)的生命周期和状态。
2、指向反馈消息的智能指针。
*/

void feedback_callback(rclcpp_action::ClientGoalHandle<Progress>::SharedPtr goal_handle,const std::shared_ptr<Progress::Feedback> feedbak)
{
//通过feedback获取反馈内容
int_32_t progress = (int_32_t)(feedback->progress * 100)
}

3.处理最终响应(回调函数)
/*
参数:
1、通常包含一个布尔值表示目标是否成功完成,以及一个指向 Result 消息类型的共享指针,该消息包含了动作服务器返回的具体结果数据。
*/

void result_callback(const rclcpp_action::ClientGoalHandle<Progress>::WrappedResult &result)
{
//result.code
//通过状态码判断最终结果状态
if(result.code == rclcpp_action::ResultCode::SUCCEEDED)
{
//成功
}
else if(result.code == rclcpp_action::ResultCode::ABORTED)
{
//被中断
}
else if(result.code == rclcpp_action::ResultCode::CANCELED)
{
//被取消
}else
{
//未知异常
}
}

3、动作通信服务端Python核心实现
“”"
1.导包;
2.初始化 ROS2 客户端;
3.定义节点类;
3-1.创建动作服务端;
3-2.生成连续反馈;
3-3.生成最终响应。
4.调用spin函数,并传入节点对象;
5.释放资源。
“”"
1.导包

import rclpy
from rclpy.action import ActionServer
from rclpy.node import Node
from base_interfaces_demo.action  import Progress

3.定义节点类
Tips:
其中处理请求数据实现和处理取消任务请求实现都有默认函数,可根据需求进行重写实现。

3-1.创建动作服务端
ActionServer(node,action_type,action_name,execute_callback)
API:创建动作通信服务端
ActionServer()

/*
参数:
1、ActionServer创建时所依赖的节点(node)
2、动作通信接口类型(action_type)
3、将服务端和客户端关联在一起的话题名称(action_name)
4、进行主逻辑的回调函数(execute_callback)
返回值:
*/
self._action_server = ActionServer(
self,
Progress,
‘get_sum’,
self.execute_callback
)
3-2.生成连续反馈并生成最终响应
goal_handle的类型是ServerGoalHandle类型的,里面包含了各种方法。

def exeute_callback(self,goal_handle)
{
    
***3-2-1.生成连续反馈***
feedback_msg = Progress.Feedback()
feedback_msg.progress = i / goal_handle.request.num
goal_handle.publish_feedback(feedback_msg)
***3-2-2.响应最终结果***
goal_handle.succeed()
result = Progress.Result()
return result
}

4.动作通信客户端Python核心实现
“”"
1.导包;
2.初始化 ROS2 客户端;
3.定义节点类;
3-1.创建动作客户端;
3-2.发送请求;
3-3.处理目标发送后的反馈;
3-4.处理连续反馈;
3-5.处理最终响应。
4.调用spin函数,并传入节点对象;
5.释放资源。

“”"
1.导包

import rclpy
from rclpy.action import ActionClient
from rclpy.node import Node
from base_interfaces_demo.action import Progress

3.定义节点类

3-1.创建动作客户端

self._action_client = ActionClient(self,Progress,'get_sum')
API:创建动作客户端
ActionClient(node,action_type,action_name)
/*
参数:
1、构建ActionClient时所依赖的节点
2、动作通信服务接口
3、动作服务端和客户端关联的话题
*/

3-2.发送请求

goal = Progress.Goal()
goal.num = num
self.aaction_client.wait_for_server()
self.future = self.action_client.send_goal_async(goal,self.fb_callback)
self.future.add_done_callback(self.goal_response_callback)

3-2-1.等待连接服务器

self.action_client.wait_for_server()//一直等待服务端连接
API:等待服务端连接
wait_for_server(timeout)

/*
参数:
1、超时时间
*/

3-2-2.发送具体请求

API:异步发送目标请求
send_goal_async(goal_msg,feed_callback)
/*
1、目标数据goal
2、回调函数feed_callback
返回值:返回一个ClientGoalHandle类型的Future对象
/
API:添加一个回调函数
add_done_callback(callback)
/

这是future下的函数,也就是ClientGoalHandle类下的成员函数
参数:
1、回调函数
*/
3-3.处理目标发送后的反馈
def goal_response_callback(self,future)
3-3-1.获取目标句柄
API:用于异步获取并返回操作结果,有阻塞行为
future.result()

goal_handle = future.result()

3-3-2.判断目标是否被服务器正常接收
API:goal_handle对象的一个属性,用于检查目标是否被action server接受。
goal_handle.accepted()
API:用于异步获取目标的最终结果,没有阻塞行为,返回一个Future对象,判断结果是否可用
get_result_async()

if not goal_handle.accepted():
	return
self.result_future = goal_handle.get_result_async()
self.result_future.add_done_callback(self.get_result_callback)

3-5.处理最终响应

def get_result_callback(self.future):
	result = future.result().result

3-4.处理连续反馈

连续反馈的回调函数:

//通过fb_msg获取到连续反馈回来的数据
def fb_callback(self,fb_msg):
		progress = fb_msg.feedback.progress 

五、参数服务通信

参数服务是以共享的方式实现不同节点之间数据交互的一种通信模式
1.参数服务API实现
常用C++API:

1、创建参数服务对象
rclcpp::Parameter p1("car_name","Tiger");//参数值为字符串类型
rclcpp::Parameter p2("width",0.15); //参数值为浮点类型
2、获取参数值
as_string().c_str()
as_double()
as_int()…

RCLCPP_INFO(rclcpp::get_logger("rclcpp"),"car_name = %s", p1.as_string().c_str());
3、获取参数的键
get_name().c_str()
RCLCPP_INFO(rclcpp::get_logger("rclcpp"),"p1 name = %s", p1.get_name().c_str());
4、获取参数的数据类型
get_type_name().c_str()
RCLCPP_INFO(rclcpp::get_logger("rclcpp"),"p1 type_name = %s", p1.get_type_name().c_str());
5、将参数值转换成字符串类型
value_to_string().c_str()
RCLCPP_INFO(rclcpp::get_logger("rclcpp"),"p1 value_to_msg = %s", p1.value_to_string().c_str());

PythonAPI:

1、创建参数对象

p1 = rclpy.Parameter("car_name",value="Horse")

2、获取参数值

get_logger("rclpy").info("car_name = %s" % p1.value)

3、获取参数键

get_logger("rclpy").info("p1 name = %s" % p1.name)

2.参数服务端C++核心实现
/*
需求:编写参数服务端,设置并操作参数。
步骤:
1.包含头文件;
2.初始化 ROS2 客户端;
3.定义节点类;
3-1.声明参数;
3-2.查询参数;
3-3.修改参数;
3-4.删除参数。
4.创建节点对象指针,调用参数操作函数,并传递给spin函数;
5.释放资源。

*/
1、包含头文件

#include "rclcpp/rclcpp.hpp"

3、定义节点类
需要设置 rclcpp::NodeOptions().allow_undeclared_parameters(true),否则非法

class MinimalParameterServer : public rclcpp::Node{
   
public:
	MinimalParameterServer():Node("minimal_parameter_server_node",rclcpp::NodeOptions().allow_undeclared_parameters(true)){
   
	}

private:
}

3-1.声明参数
API:声明参数
declar_parameter()
/*
参数:
1、键
2、值
eg:
this->declar_parameter("car_name","Tiger");
*/
3-2.查询参数
API:查询参数
get_parameter("键").as_string.c_str()----获取参数的值
eg:
RCLCPP_INFO(this->get_logger(),"height:%.2f",this->get_parameter("height").as_double());

API:判断是否包含该参数
has_parameter("键")-
eg:
RCLCPP_INFO(this->get_logger(),"包含car_type? %d",this->has_parameter("car_type"));
3-3.修改参数
API:修改参数
set_parameter(需要修改的键值对)
eg:
this->set_parameter(rclcpp::Parameter("键","值"));
3-4.删除参数
API:删除参数
undeclar_parameter("键")
eg:
this->undeclar_parameter("键");

3.参数客户端C++核心实现
/*
需求:编写参数客户端,获取或修改服务端参数。
步骤:
1.包含头文件;
2.初始化 ROS2 客户端;
3.定义节点类;
3-1.查询参数;
3-2.修改参数;
4.创建节点对象指针,调用参数操作函数;
5.释放资源。
*/
1、包含头文件

#include "rclcpp/rclcpp.hpp";

3、定义节点类

3-0.等待服务器连接
API:等待服务器连接
wait_for_service(超时时间)
eg:

>paramClient = std::make_shared<rclcpp::SyncParametersClient>(this,"minimal_param_server");
>while(!paramClient->wait_for_service(1s))
>{
   
>if(!rclcpp::ok())
>{
   
>	return false;
>}
>RCLCPP_INFO(this->get_logger(),"服务未连接!");
>}

3-1.查询参数
API:查询参数
get_parameter("键")
3-2.修改参数
API:修改参数
set_parameters(rclcpp::Parameter("键","值"))

4、参数服务端Python核心实现
“”"
需求:编写参数服务端,设置并操作参数。
步骤:
1.导包;
2.初始化 ROS2 客户端;
3.定义节点类;
3-1.声明参数;
3-2.查询参数;
3-3.修改参数;
3-4.删除参数。
4.创建节点对象,调用参数操作函数,并传递给spin函数;
5.释放资源。

“”"
1、导包

import rclpy
from rclpy.node import Node

3、定义节点类

需要设置allow_undeclared_parameters = True
eg:

def __int__(self):
super().__init__("minimal_parameter_server_node",allow_undeclared_parameters = True)

3-1.声明参数
API:声明参数
declar_parameter("Key","Value")

self.declar_parameter("car_type","Tiger")

3-2.查询参数
API:判断是否包含参数键
has_parameter("Key")----判断是否包含参数键

self.get_logger().info("包含 car_type 吗?%d" % self.has_parameter("car_type"))

API:获取指定参数键的值
get_parameter("Key")----获取指定参数键的值

car_type = self.get_parameter("car_type")
self.get_logger().info("%s = %s " % (car_type.name, car_type.value))

API:获取所有参数键的值
get_parameters(["Key1","Key2","Key3"])----获取所有参数键的值

params = self.get_parameters(["car_type","height","wheels"])
self.get_logger().info("解析所有参数:")
for param in params:
    self.get_logger().info("%s ---> %s" % (param.name, param.value))

3-3.修改参数
API:修改参数
set_parameters(rclpy.Parameter("Key","Value"))

self.set_parameters([rclpy.Parameter("car_type",value = "horse")])

3-4.删除参数
API:删除参数
undeclar_parameter("Key")

self.undeclare_parameter("car_type")

4-5、参数客户端Python核心实现

暂无!

通信机制补充

1、分布式

1-1.概念:
分布式通信是指可以通过网络在不同主机之间实现数据交互的一种通信策略
1-2.实现:
多机通信时通过域ID对节点进行分组,每组的不同节点之间可以自由通信,不同组之间的节点不可以进行通信
export ROS_DOMAIN_ID = 2
如果为当前设备下所有节点设置统一的域ID,可以执行以下指令:
echo "export ROS_DOMAIN_ID = 2" >> ~.bashrc
注意:

1、ROS_DOMAIN_ID的值在[0,101]之间
2、每个域ID内的节点总数需要小于等于120个
3、当域ID =101时,该域内的节点总数需要小于等于54个。

1-3.DDS域ID的计算规则:
1、DDS基于TCP/IP和UDP/IP网络通信协议,网络通信需要端口号,一个端口号占两个字节,取值范围为[0,65535]
2、DDS协议规定以7400为起始端口,默认每个域ID占250个端口,故域ID的个数为(65535-7400)/250 = 232(个),对应的其取值范围为[0,231]
3、操作系统会预留一些端口,不同操作系统预留端口有差异:Linux系统下,域ID为[0,101]和[215,231];MAC和Windows可用域ID为:[0,166]
4、每个域ID默认占用250个端口,每个ROS2节点需要占用两个端口,按照DDS协议每个域ID的端口段内,第1、2个端口是Discovery Multicast端口与User Multicast端口,从第11、12个端口开始是域内第一个节点的Discovery Unicast端口与User Unicast,后续节点所占用端口依次顺延,那么一个域ID中的最大节点个数为:(250-10)/2 = 120(个);
5、特殊情况:域ID值为101时,其后半段端口属于操作系统的预留端口,其节点最大个数为54个。

>域 ID 与节点所占用端口示意:
Domain ID:      0
Participant ID: 0

Discovery Multicast Port: 7400
User Multicast Port:      7401
Discovery Unicast Port:   7410
User Unicast Port:        7411

---

Domain ID:      1
Participant ID: 2
Discovery Multicast Port: 7650
User Multicast Port:      7651
Discovery Unicast Port:   7664
User Unicast Port:        7665

2、工作空间覆盖

1、概念
不同工作空间存在重名功能包时,重名功能包的调用会出现覆盖的情况。
这种情况需要极力避免的。
2、原因:
这与~/.bashrc中不同工作空间的setup.bash文件的加载顺序有关
1、ROS2首先解析 ~/.bashrc文件并生成全局变量AMENT_PREFIX_PATH 与 PYTHONPATH
2、.两个变量的值的设置与 ~/.bashrc 中的 setup.bash 的配置顺序有关
3、调用功能包时,会按照 AMENT_PREFIX_PATH 或 PYTHONPATH 中包配置顺序从前往后依次查找相关功能包

3、元功能包

将不同的功能包打包成一个功能包,安装某个功能模块时,直接调用打包后的功能包(MetaPackage)
1、实现
ros2 pkg create 功能包
ros2 pkg create tutorails_plumbing

2、配置package.xml

<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
  <name>tutorails_plumbing</name>
  <version>0.0.0</version>
  <description>TODO: Package description</description>
  <maintainer email="ros2@todo.todo">ros2</maintainer>
  <license>TODO: License declaration</license>

  <buildtool_depend>ament_cmake</buildtool_depend>

  <exec_depend>base_interfaces_demo</exec_depend>
  <exec_depend>cpp01_topic</exec_depend>
  <exec_depend>cpp02_service</exec_depend>
  <exec_depend>cpp03_action</exec_depend>
  <exec_depend>cpp04_param</exec_depend>
  <exec_depend>py01_topic</exec_depend>
  <exec_depend>py02_service</exec_depend>
  <exec_depend>py03_action</exec_depend>
  <exec_depend>py04_param</exec_depend>


  <export>
    <build_type>ament_cmake</build_type>
  </export>
</package>

3、配置CmakeList.txt

cmake_minimum_required(VERSION 3.8)
project(tutorails_plumbing)

if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  add_compile_options(-Wall -Wextra -Wpedantic)
endif
  • 37
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: ROS2的源码是指ROS2软件框架的实现源代码,其中包含了ROS2的核心功能实现及相关库和工具的源代码。 赵虚C是指赵虚所编写的ROS2 C语言版本的源码。赵虚C源码是一种使用C语言实现的ROS2框架源码,它基于ROS2的设计理念和规范,实现了ROS2的核心功能。 在赵虚C源码中,可以看到ROS2中的许多重要概念和组件的实现,包括节点(Node)、话题(Topic)、服务(Service)和参数(Parameter)等。通过阅读这些源码,可以深入理解ROS2的工作原理和实现细节,以便于进行二次开发和定制化。 此外,赵虚C源码还包含了ROS2的通信机制、消息传输和序列化等关键部分的实现。通过分析这些源码,可以了解ROS2是如何处理节点之间的通信、数据的传输和消息的序列化与反序列化的过程。 总之,赵虚C源码是ROS2的一种具体实现,通过对它的研究和理解,可以深入了解ROS2的内部机制和工作原理,为ROS2的应用开发和定制提供参考和基础。 ### 回答2: ROS 2(Robot Operating System 2)是一个用于开发机器人机器人系统的开源框架。而"赵虚 c"是一个源码工程师,可能是ROS 2框架的贡献者之一,他在其中的C++源码方面进行了贡献。 ROS 2是ROS框架的下一代版本,它提供了更强大、更灵活的功能,使得开发机器人应用更加简单和高效。与ROS 1相比,ROS 2在可扩展性、实时性、安全性和分布式系统方面有了进一步的改进。 "赵虚 c"可能是一个开发者,他在ROS 2源码中使用了C++语言来为框架做出贡献。C++是一种通用的、高级的编程语言,常用于开发复杂的系统和应用。在ROS 2中,C++用于编写框架的核心功能、通信模块、节点等。 作为一个源码工程师,"赵虚 c"可能参与了ROS 2的开发过程,贡献了自己的代码和思想。他可能在ROS 2的源码中实现了一些功能模块、优化了代码结构、提高了系统的性能,或者修复了一些bug。 通过贡献C++源码,"赵虚 c"可能帮助改进了ROS 2框架,使得它更加稳定、高效、易用。源码工程师的工作是为了让软件系统能够更好地满足用户需求,提供良好的开发体验和性能。 总结来说,"ros2 赵虚 c"源码可能指的是ROS 2框架中贡献者赵虚C++源码。他通过自己的工作,为ROS 2框架的发展和改进做出了贡献。 ### 回答3: ROS 2是Robot Operating System(机器人操作系统)的第二个主要版本。相比于ROS 1,ROS 2在一些方面进行了改进和优化。其中ROS 2的核心部分就是ROS 2的源码,它包含了ROS 2系统的各个模块和功能的实现。 赵虚C是ROS 2中的一个模块,它是基于C语言编写的。赵虚C的作用是提供一些ROS 2系统中常用的功能,比如节点节点的创建与运行、消息的发布与订阅等。赵虚C的源码中包含了一些函数和数据结构,通过这些函数和数据结构,开发者可以在自己的ROS 2应用程序中调用和使用这些功能。 赵虚C源码的结构比较清晰,它按照模块和功能进行了组织。赵虚C的源码中使用了一些ROS 2的API和库函数,这些函数通过ROS 2的底层实现来完成特定的功能。在理解赵虚C源码时,需要对ROS 2的相关概念和机制有所了解,比如节点的概念、消息的定义与传输、话题的订阅与发布等。 通过阅读赵虚C源码,可以更深入地理解ROS 2系统的运行原理和实现细节。同时,开发者也可以基于赵虚C的源码进行二次开发,实现自己的ROS 2应用程序,以满足特定的需求。 总之,赵虚C是ROS 2中的一个重要模块,通过阅读其源码可以更好地理解和使用ROS 2系统。对于ROS 2开发者来说,熟悉赵虚C源码是提高开发效率和质量的一种有效途径。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值