网站开发谢辞,山西住房和建设厅网站,网页首页管理系统,做外贸 上国外网站目录 0 专栏介绍1 话题通信模型2 话题模型实现(C)3 话题模型实现(Python)4 自定义消息 0 专栏介绍
本专栏旨在通过对ROS2的系统学习#xff0c;掌握ROS2底层基本分布式原理#xff0c;并具有机器人建模和应用ROS2进行实际项目的开发和调试的工程能力。
#x1f680;详情)3 话题模型实现(Python)4 自定义消息 0 专栏介绍
本专栏旨在通过对ROS2的系统学习掌握ROS2底层基本分布式原理并具有机器人建模和应用ROS2进行实际项目的开发和调试的工程能力。
详情《ROS2从入门到精通》 1 话题通信模型
话题是一种单向通信通道数据或信息以定义的格式传递其中。机器人组件可以订阅主题以接收信息或者发布信息到主题以与其他组件分享。其中发布信息的节点称为发布者接受信息的节点称为订阅者 举个例子想象一个移动机器人其中有一个负责读取传感器数据的组件另一个负责控制电机。传感器组件可以在名为sensor_readings的话题中发布传感器读数信息。同时控制组件可以订阅此话题以接收该信息并用于控制电机。
在 ROS 2 中话题由中间件管理以确保消息可靠高效地传输。话题中的消息可以是任何可序列化的数据类型例如整数、浮点数、字符串、矩阵等。
ROS 2 中的话题具有多对多通信的灵活性和可扩展性。例如可以有多个组件订阅同一话题或者多个组件发布数据到同一主题。此外可以使用线程来连接单个机器人内部的组件或者在网络中连接不同机器人之间的组件。 2 话题模型实现(C) 实验目标发布者发布控制消息到/turtle1/cmd_vel控制乌龟其做圆周运动订阅者订阅/turtle1/cmd_vel在终端显示乌龟实时的位置坐标。 发布者 class PublisherNode : public rclcpp::Node
{public:PublisherNode() : Node(lab_topic_pub) {publisher_ create_publishergeometry_msgs::msg::Twist(/turtle1/cmd_vel, 10); }void publish(geometry_msgs::msg::Twist msg) {publisher_-publish(msg);}private:rclcpp::Publishergeometry_msgs::msg::Twist::SharedPtr publisher_;
};int main(int argc, char * argv[])
{rclcpp::init(argc, argv); auto node std::make_sharedPublisherNode();rclcpp::Rate loop_rate(10);while(rclcpp::ok()) {auto msg geometry_msgs::msg::Twist();msg.linear.x 0.5;msg.angular.z 0.2;node-publish(msg);RCLCPP_INFO(node-get_logger(), Publishing: x: %.2f, z: %.2f, msg.linear.x, msg.angular.z);loop_rate.sleep();} rclcpp::shutdown(); return 0;
}订阅者(订阅的话题存在消息即触发回调函数) class SubscriberNode : public rclcpp::Node
{public:SubscriberNode() : Node(lab_topic_sub){subscriber_ create_subscriptiongeometry_msgs::msg::Twist( /turtle1/cmd_vel, 10, std::bind(SubscriberNode::OnPoseCallback, this, _1));}private:void OnPoseCallback(const geometry_msgs::msg::Twist msg) const{RCLCPP_INFO(get_logger(), Publishing: x: %.2f, z: %.2f, msg.linear.x, msg.angular.z);}rclcpp::Subscriptiongeometry_msgs::msg::Twist::SharedPtr subscriber_;
};int main(int argc, char * argv[])
{rclcpp::init(argc, argv); rclcpp::spin(std::make_sharedSubscriberNode()); rclcpp::shutdown(); return 0;
}话题通信的效果如下所示 计算图可视化为 3 话题模型实现(Python) 实验目标发布者发布控制消息到/turtle1/cmd_vel控制乌龟其做圆周运动订阅者订阅/turtle1/cmd_vel在终端显示乌龟实时的位置坐标。 发布者class PublisherNode(Node):def __init__(self, name):super().__init__(name) self.publisher_ self.create_publisher(Twist, /turtle1/cmd_vel, 10) def publish(self, msg: Twist):self.publisher_.publish(msg)订阅者class SubscriberNode(Node):def __init__(self, name):super().__init__(name)self.subscirber_ self.create_subscription(Twist, /turtle1/cmd_vel, self.OnPoseCallback, 10) def OnPoseCallback(self, msg):self.get_logger().info(fPublishing: x: {msg.linear.x:.2f}, z: {msg.angular.z:.2f})def main(argsNone): rclpy.init(argsargs) node SubscriberNode(lab_topic_sub)rclpy.spin(node) node.destroy_node() rclpy.shutdown() 话题通信的效果如下所示 4 自定义消息
ROS2系统通过std_msgs封装了一些常用的原生数据类型比如String、Int32、Int64等对于一些复杂数据应用场景往往需要在std_msgs或其他消息库的基础上继续封装更高级的数据类型
自定义消息的通用流程如下 功能包下新建msg文件夹在其中添加自定义消息xxx.msg功能包package.xml中添加编译依赖与执行依赖buildtool_dependrosidl_default_generators/buildtool_depend
exec_dependrosidl_default_runtime/exec_depend
member_of_grouprosidl_interface_packages/member_of_group功能包CMakeLists.txt中添加编译消息相关依赖find_package(rosidl_default_generators REQUIRED)
rosidl_generate_interfaces(${PROJECT_NAME}xxx.msgDEPENDENCIES xxx_msgs
)ament_export_dependencies(rosidl_default_runtime)编译自定义消息在install/pkg_name/include中生成由xxx.msg编译的C可识别的xxx.hpp头文件引入xxx.hpp即可调用自定义消息 下面给出一个实例
添加如下自定义消息并按上面步骤配置依赖
# Person.msg
string name
string gender
uint8 agegeometry_msgs/Point positionfloat64 xfloat64 yfloat64 z定义一个发布者、一个订阅者测试自定义消息
发布者// 初始化名为personPub的ROS节点, 该节点应在CMakeLists.txt中被构建为可执行文件
ros::init(argc, argv, personPub);
// 创建节点句柄
ros::NodeHandle pubNode;
// 创建发布者, 该发布者属于pubNode节点, 发布话题为/person/info,
// 消息类型为msgtest::Person, 发布队列长度为10
ros::Publisher pub pubNode.advertisemsg_lab::Person(/person/info, 10);
// 设置发布频率
ros::Rate loopRate(10);
while(ros::ok())
{// 设置消息msg_lab::Person msg;msg.name winter;msg.gender man;msg.age 20;msg.position.x 10;msg.position.y 20;msg.position.z 30;// 发布消息pub.publish(msg);ROS_INFO(Publish Person Info[name: %s gender: %s age: %d pos: x-%.2f y-%.2f z-%.2f], msg.name.c_str(), msg.gender.c_str(), msg.age, msg.position.x, msg.position.y, msg.position.z);// 按循环频率延时loopRate.sleep();
}订阅者void personInfoCallBack(const msg_lab::Person::ConstPtr msg)
{ROS_INFO(Subscribe Person Info[name: %s gender: %s age: %d pos: x-%.2f y-%.2f z-%.2f], msg-name.c_str(), msg-gender.c_str(), msg-age, msg-position.x, msg-position.y, msg-position.z);
}int main(int argc, char** argv)
{// 初始化名为personSub的ROS节点, 该节点应在CMakeLists.txt中被构建为可执行文件ros::init(argc, argv, personSub);// 创建节点句柄ros::NodeHandle subNode;// 创建订阅者, 该订阅者属于subNode节点, 订阅话题为/person/info,// 订阅队列长度为10, 收到订阅消息后出发回调函数personInfoCallBackros::Subscriber sub subNode.subscribe(/person/info, 10, personInfoCallBack);// 循环等待回调函数ros::spin();return 0;
}实测效果如下 完整代码通过下方博主名片联系获取 更多精彩专栏
《ROS从入门到精通》《Pytorch深度学习实战》《机器学习强基计划》《运动规划实战精讲》… 源码获取 · 技术交流 · 抱团学习 · 咨询分享 请联系