ROS2开发机器人移动
.创建功能包和节点
这里我们设计两个节点
example_interfaces_robot_01,机器人节点,对外提供控制机器人移动服务并发布机器人的状态。
example_interfaces_control_01,控制节点,发送机器人移动请求,订阅机器人状态话题。
创建节点
ros2 pkg create example_interfaces_rclcpp --build-type ament_cmake --dependencies rclcpp example_ros2_interfaces --destination-directory src --node-name example_interfaces_robot_01
touch src/example_interfaces_rclcpp/src/example_interfaces_control_01.cpp
#include "rclcpp/rclcpp.hpp"
#include "example_ros2_interfaces/srv/move_robot.hpp"
#include "example_ros2_interfaces/msg/robot_status.hpp"
class ExampleInterfacesControl : public rclcpp::Node {
public:
ExampleInterfacesControl(std::string name) : Node(name) {
RCLCPP_INFO(this->get_logger(), "节点已启动:%s.", name.c_str());
/*创建move_robot客户端*/
client_ = this->create_client<example_ros2_interfaces::srv::MoveRobot>(
"move_robot");
/*订阅机器人状态话题*/
robot_status_subscribe_ = this->create_subscription<example_ros2_interfaces::msg::RobotStatus>("robot_status", 10, std::bind(&ExampleInterfacesControl::robot_status_callback_, this, std::placeholders::_1));
}
/**
* @brief 发送移动机器人请求函数
* 步骤:1.等待服务上线
* 2.构造发送请求
*
* @param distance
*/
void move_robot(float distance) {
RCLCPP_INFO(this->get_logger(), "请求让机器人移动%f", distance);
/*等待服务端上线*/
while (!client_->wait_for_service(std::chrono::seconds(1))) {
//等待时检测rclcpp的状态
if (!rclcpp::ok()) {
RCLCPP_ERROR(this->get_logger(), "等待服务的过程中被打断...");
return;
}
RCLCPP_INFO(this->get_logger(), "等待服务端上线中");
}
// 构造请求
auto request =
std::make_shared<example_ros2_interfaces::srv::MoveRobot::Request>();
request->distance = distance;
// 发送异步请求,然后等待返回,返回时调用回调函数
client_->async_send_request(
request, std::bind(&ExampleInterfacesControl::result_callback_, this,
std::placeholders::_1));
};
private:
// 声明客户端
rclcpp::Client<example_ros2_interfaces::srv::MoveRobot>::SharedPtr client_;
rclcpp::Subscription<example_ros2_interfaces::msg::RobotStatus>::SharedPtr robot_status_subscribe_;
/* 机器人移动结果回调函数 */
void result_callback_(
rclcpp::Client<example_ros2_interfaces::srv::MoveRobot>::SharedFuture
result_future) {
auto response = result_future.get();
RCLCPP_INFO(this->get_logger(), "收到移动结果:%f", response->pose);
}
/**
* @brief 机器人状态话题接收回调函数
*
* @param msg
*/
void robot_status_callback_(const example_ros2_interfaces::msg::RobotStatus::SharedPtr msg)
{
RCLCPP_INFO(this->get_logger(), "收到状态数据位置:%f 状态:%d", msg->pose ,msg->status);
}
};
int main(int argc, char** argv) {
rclcpp::init(argc, argv);
auto node = std::make_shared<ExampleInterfacesControl>("example_interfaces_control_01");
/*这里调用了服务,让机器人向前移动5m*/
node->move_robot(5.0);
rclcpp::spin(node);
rclcpp::shutdown();
return 0;
}
编写机器人节点逻辑
example_interfaces_robot_01.cpp
#include "example_ros2_interfaces/msg/robot_status.hpp"
#include "example_ros2_interfaces/srv/move_robot.hpp"
#include "rclcpp/rclcpp.hpp"
/*创建一个机器人类,模拟真实机器人*/
class Robot {
public:
Robot() = default;
~Robot() = default;
/**
* @brief 移动指定的距离
*
* @param distance
* @return float
*/
float move_distance(float distance) {
status_ = example_ros2_interfaces::msg::RobotStatus::STATUS_MOVEING;
target_pose_ += distance;
// 当目标距离和当前距离大于0.01则持续向目标移动
while (fabs(target_pose_ - current_pose_) > 0.01) {
// 每一步移动当前到目标距离的1/10
float step = distance / fabs(distance) * fabs(target_pose_ - current_pose_) * 0.1;
current_pose_ += step;
std::cout << "移动了:" << step << "当前位置:" << current_pose_ << std::endl;
// 当前线程休眠500ms
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
status_ = example_ros2_interfaces::msg::RobotStatus::STATUS_STOP;
return current_pose_;
}
/**
* @brief Get the current pose
*
* @return float
*/
float get_current_pose() { return current_pose_; }
/**
* @brief Get the status
*
* @return int
* 1 example_ros2_interfaces::msg::RobotStatus::STATUS_MOVEING
* 2 example_ros2_interfaces::msg::RobotStatus::STATUS_STOP
*/
int get_status() { return status_; }
private:
// 声明当前位置
float current_pose_ = 0.0;
// 目标距离
float target_pose_ = 0.0;
int status_ = example_ros2_interfaces::msg::RobotStatus::STATUS_STOP;
};
class ExampleInterfacesRobot : public rclcpp::Node {
public:
ExampleInterfacesRobot(std::string name) : Node(name) {
RCLCPP_INFO(this->get_logger(), "节点已启动:%s.", name.c_str());
/*创建move_robot服务*/
move_robot_server_ = this->create_service<example_ros2_interfaces::srv::MoveRobot>(
"move_robot", std::bind(&ExampleInterfacesRobot::handle_move_robot, this, std::placeholders::_1, std::placeholders::_2));
/*创建发布者*/
robot_status_publisher_ = this->create_publisher<example_ros2_interfaces::msg::RobotStatus>("robot_status", 10);
/*创建一个周期为500ms的定时器*/
timer_ = this->create_wall_timer(std::chrono::milliseconds(500), std::bind(&ExampleInterfacesRobot::timer_callback, this));
}
private:
Robot robot; /*实例化机器人*/
rclcpp::TimerBase::SharedPtr timer_; /*定时器,用于定时发布机器人位置*/
rclcpp::Service<example_ros2_interfaces::srv::MoveRobot>::SharedPtr move_robot_server_; /*移动机器人服务*/
rclcpp::Publisher<example_ros2_interfaces::msg::RobotStatus>::SharedPtr robot_status_publisher_; /*发布机器人位姿发布者*/
/**
* @brief 500ms 定时回调函数,
*
*/
void timer_callback() {
// 创建消息
example_ros2_interfaces::msg::RobotStatus message;
message.status = robot.get_status();
message.pose = robot.get_current_pose();
RCLCPP_INFO(this->get_logger(), "Publishing: %f", robot.get_current_pose());
// 发布消息
robot_status_publisher_->publish(message);
};
/**
* @brief 收到话题数据的回调函数
*
* @param request 请求共享指针,包含移动距离
* @param response 响应的共享指针,包含当前位置信息
*/
void handle_move_robot(const std::shared_ptr<example_ros2_interfaces::srv::MoveRobot::Request> request,
std::shared_ptr<example_ros2_interfaces::srv::MoveRobot::Response> response) {
RCLCPP_INFO(this->get_logger(), "收到请求移动距离:%f,当前位置:%f", request->distance, robot.get_current_pose());
robot.move_distance(request->distance);
response->pose = robot.get_current_pose();
};
};
int main(int argc, char** argv) {
rclcpp::init(argc, argv);
auto node = std::make_shared<ExampleInterfacesRobot>("example_interfaces_robot_01");
rclcpp::spin(node);
rclcpp::shutdown();
return 0;
}
编译运行节点
colcon build --packages-up-to example_interfaces_rclcpp
控制端
source install/setup.bash
ros2 run example_interfaces_rclcpp example_interfaces_control_01
服务端
source install/setup.bash
ros2 run example_interfaces_rclcpp example_interfaces_robot_01
相关文章:
ROS2开发机器人移动
.创建功能包和节点 这里我们设计两个节点 example_interfaces_robot_01,机器人节点,对外提供控制机器人移动服务并发布机器人的状态。 example_interfaces_control_01,控制节点,发送机器人移动请求,订阅机器人状态话题…...
【强化学习】第02期:动态规划方法
笔者近期上了国科大周晓飞老师《强化学习及其应用》课程,计划整理一个强化学习系列笔记。笔记中所引用的内容部分出自周老师的课程PPT。笔记中如有不到之处,敬请批评指正。 文章目录 2.1 动态规划:策略收敛法/策略迭代法2.2 动态规划…...
安全技术和防火墙(二)
接上一节 备份和还原 iptables-save > /opt/iptables.bak iptables-restore < /opt/iptables.bak snat和dnat snat源地址转换 内网到外网 内网ip转换成可以访问外网的ip 内网的多个主机可以只有一个有效的公网ip地址访问外部网络 dnat 目的地址转发 外部用户&#…...
【51单片机入门】数码管原理
文章目录 前言共阴极与共阳极数码管多个数码管显示原理 总结 前言 在我们的日常生活中,数码管被广泛应用于各种电子设备中,如电子表、计时器、电子钟等。数码管的主要功能是显示数字和一些特殊字符。在这篇文章中,我们将探讨数码管的工作原理…...
三星DRAM、NAND,“又双叒叕”带头涨价了
据韩国媒体《每日经济新闻》报道,三星电子计划在第三季度上调服务器DRAM和企业级NAND闪存的价格,涨幅预计在15%-20%,主要受人工智能(AI)需求激增的推动。这一举措有望提振公司下半年业绩。 据《经济日报》报道援引业内消息,由于厂…...
星戈瑞FITC-PEG2000-Biotin的生物相容性
生物相容性是指材料与生物体之间相互作用时,材料对生物体无毒、无刺激,且能够被生物体接受并正常发挥其功能的特性。 FITC-PEG2000-Biotin作为一种荧光标记试剂,在细胞成像、药物传递和生物标志物检测等领域具有诸多应用前景。 FITC-PEG2000…...
数据资产管理的艺术:构建智能化、精细化的数据资产管理体系,从数据整合、分析到决策支持,为企业提供一站式的数据资产解决方案,助力企业把握数字时代的新机遇
一、引言 在数字化浪潮席卷全球的今天,数据已经成为企业最重要的资产之一。如何高效、安全地管理这些海量数据,从中提取有价值的信息,并将其转化为决策支持,是每个企业都必须面对的挑战。本文将探讨数据资产管理的艺术࿰…...
基于Java微信小程序校园自助打印系统设计和实现(源码+LW+调试文档+讲解等)
💗博主介绍:✌全网粉丝10W,CSDN作者、博客专家、全栈领域优质创作者,博客之星、平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌💗 🌟文末获取源码数据库🌟感兴趣的可以先收藏起来,还…...
股票复盘思路
股票复盘是一个回顾和分析市场及个人交易决策的过程,旨在从过去的表现中学习并优化未来的投资策略。以下是一些基本的股票复盘步骤和关注点: 市场概况回顾: 观察并记录每日市场的整体表现,包括大盘指数涨跌、成交量变化。统计涨停和跌停个股的数量,了解市场情绪和活跃度。…...
OpenGL系列(六)摄像机
在 OpenGL系列(六)变换 中,一个目标物体经过模型矩阵、观察矩阵和投影矩阵的变换才能正常显示出来,其中模型矩阵主要针对目标物体,它会影响物体的位姿。观察矩阵和投影矩阵主要针对观察者而已,这两个变换决…...
一个端口配置两个vue和后端服务,nginx以及前后端服务怎么配?
nginx配置重点看server中的内容: worker_processes 8; pid /usr/local/nginx/logs/nginx.pid;events {# 此为 Linux 系统特为处理大批量文件描述符而作改进的 poll 事件模型use epoll;worker_connections 512; # 工作进程的最大连接数量# 允许同时接受多个网络连…...
295. 数据流的中位数
class MedianFinder {Queue<Integer> A,B;public MedianFinder() {A new PriorityQueue<>();//小根堆存储后半部分B new PriorityQueue<>((x,y)->(y-x));//大根堆存储前半部分}public void addNum(int num) {if(A.size()0 && B.size()0){B.add(…...
OCR训练和C#部署英文字符训练
PaddleOCR是一个基于飞桨开发的OCR(Optical Character Recognition,光学字符识别)系统。其技术体系包括文字检测、文字识别、文本方向检测和图像处理等模块。以下是其优点: 高精度:PaddleOCR采用深度学习算法进行训练…...
webpack【实用教程】
基础配置 配置的拆分和合并 通常 webpack 的配置文件会有3个 webpack.common.js 公共配置(会被另外两个配置文件导入并合并)webpack.dev.js 开发环境的配置webpack.prod.js 生产环境的配置 开发环境的本地服务 在 webpack.dev.js 中配置 devServer:…...
如何使用C++进行文件读写操作
在C中,我们可以使用标准库中的 <fstream>(文件流)来进行文件的读写操作。以下是一些基本的文件读写操作的示例。 读取文件 cpp复制代码 #include <fstream> #include <iostream> #include <string> int main() { s…...
Tensorflow Lite移动平台编译
Android平台编译 如果不做定制化操作,我们不需要自己编译TensorFlow Lite Android库。我们可以直接使用位于MavenCentral的TensorFlow Lite AAR。但是在某些情况下,我们需要本地编译TensorFlow Lite。例如,您可能正在构建一个包含operations selected from TensorFlow的自定…...
2024年6月24日-6月30日(ue5肉鸽视频p16-p25)
试过重点放在独立游戏上,有个indienova独立游戏团队是全职的,由于他们干了几个月,节奏暂时跟不上,紧张焦虑了。五一时也有点自暴自弃了,实在没必要,按照自己的节奏走即可。精力和时间也有限,放在…...
LeetCode.面试题17.24.最大子矩阵详解
问题描述 给定一个正整数、负整数和 0 组成的 N M 矩阵,编写代码找出元素总和最大的子矩阵。 返回一个数组 [r1, c1, r2, c2],其中 r1, c1 分别代表子矩阵左上角的行号和列号,r2, c2 分别代表右下角的行号和列号。若有多个满足条件的子矩阵…...
云动态摘要 2024-06-28
给您带来云厂商的最新动态,最新产品资讯和最新优惠更新。 最新优惠与活动 [新客专享]WeData 限时特惠 腾讯云 2024-06-21 数据分类分级管理,构建数据安全屏障 ,仅需9.9元! 云服务器ECS试用产品续用 阿里云 2024-04-14 云服务器…...
六、资产安全—信息分级资产管理与隐私保护(CISSP)
目录 1.信息分级 2.信息分级方法 3.责任的层级 4.资产管理 5.隐私数据管理角色 6.数据安全控制 7.数据保护方案 8.使用安全基线 六、资产安全—数据管理(CISSP): 五、身份与访问管理—身份管理和访问控制管理(CISSP): 1.信息分级 信息分级举列: 2.信息分级方…...
香港服务器托管对外贸行业必要性和优势
在当今全球化的经济环境下,外贸企业面临着前所未有的机遇与挑战。其中,服务器托管的选择对于外贸企业的运营效率和市场拓展具有举足轻重的作用。香港服务器,凭借其独特的地理位置、优质的网络环境和卓越的服务性能,一直是外贸企业…...
Vue Router 导航守卫,多次执行的解决方案
Vue Router 是 Vue.js 官方提供的路由器,它用于处理单页应用(SPA)中的路由导航。在 Vue Router 中,导航守卫是非常重要的功能,它可以在路由跳转之前或之后执行一些特定的操作。但是,如果你不小心,导航守卫可能会多次执行,这可能会导致一些问题。本文将介绍如何避免导航…...
SpringBoot集成道历(实现道历日期查询)
官网地址:官网地址https://6tail.cn/calendar/api.html 1、导入依赖 <dependency><groupId>cn.6tail</groupId><artifactId>lunar</artifactId><version>1.3.9</version></dependency><dependency><group…...
面对.rmallox勒索病毒:如何有效防范及应对
引言: 在当今数字化社会,网络安全问题日益严重,勒索病毒成为企业和个人不可忽视的威胁之一。最近出现的.rmallox勒索病毒更是给全球各地的用户带来了严重的数据安全问题。本文将探讨.rmallox勒索病毒的特点、感染方式及应对策略,…...
嘉立创学习
1.两个设置,一般用左边那个 2.焊盘分类 基本焊盘 热风盘:也叫花焊盘(负片) 隔离焊盘:外面那圈黑色,用作隔离(负片) 钢网层:(锡膏) 阻焊层&…...
ECharts 响应式设计
ECharts 响应式设计 ECharts 是一个由百度开源的,基于 JavaScript 的可视化库,它提供了一系列丰富的图表类型和灵活的配置选项,使得数据可视化变得简单而高效。在当今数据驱动的世界中,ECharts 已经成为许多开发者和设计师的首选工具,用于创建交互式和视觉吸引力强的图表…...
基于java语言+springboot技术架构开发的 互联网智能3D导诊系统源码支持微信小程序、APP 医院AI智能导诊系统源码
基于java语言springboot技术架构开发的 互联网智能3D导诊系统源码支持微信小程序、APP 医院AI智能导诊系统源码 一、智慧导诊系统开发原理 导诊系统从原理上大致可分为基于规则模板和基于数据模型两类。 1、基于规则推理的方法通过人工建立症状、疾病和科室之间的对应规则实现…...
MySQL事务——Java全栈知识(31)
1、事务的特性 原子性(Atomicity):事务是不可分割的最小操作单元,要么全部成功,要么全部失败。 一致性(Consistency):事务完成时,必须使所有的数据都保持一致状态。 隔离…...
2毛钱不到的2A同步降压DCDC电压6V频率1.5MHz电感2.2uH封装SOT23-5芯片MT3520B
前言 2A,2.3V-6V输入,1.5MHz 同步降压转换器,批量价格约0.18元 MT3520B 封装SOT23-5 丝印AS20B5 特征 高效率:高达 96% 1.5MHz恒定频率操作 2A 输出电流 无需肖特基二极管 2.3V至6V输入电压范围 输出电压低至 0.6V PFM 模式可在…...
Ubuntu安装、更新和删除软件
Ubuntu安装、更新和删除软件 问题命令行直接安装、更新和删除软件命令行直接安装软件命令行直接更新软件命令行直接删除软件 手动下载后命令行安装、更新和删除软件手动下载后命令行安装软件手动下载后命令行更新软件手动下载后命令行删除软件 手动下载后在桌面环境下安装、更新…...
otc场外交易网站开发/推广营销企业
我们在使用IBM SPSS Statistics来进行数据分析的时候,难免会遇上这种情况:变量非常多,多到我们不能对其一一控制的地步,但每个变量都有分析的价值,同时又彼此重叠。这个时候最直接的方法就是把所有变量按照一定的标准来进行分类&a…...
网站ico添加/跟我学seo
JDK环境变量的配置 新建->变量名"JAVA_HOME",变量值"C:\Program Files\Java\jdk1.8.0_291"(即JDK的安装路径) 编辑->变量名"Path",点击"新建",然后输入上"%JAVA…...
wordpress网站迁移问题/爱站网站长seo综合查询
什么是拦截器 1.SpringMVC框架中的拦截器用于 对处理器 进行预处理和后处理的技术。 2.可以定义拦截器链,按照顺序执行。 3.拦截器和过滤器功能类似,区别在 拦截器过滤器过滤器是Servlet规范的一部分,任何框架都可以使用过滤技术。而拦截器是…...
有域名了 怎么做网站/seo建设
如果你频繁的在你的系统中安装/卸载,那么不时的清理一下你的系统是十分必要的。 在Ubuntu终端中执行如下命令:sudo apt-get autoremove屏幕输出是这个样子的: Reading package lists… DoneBuilding dependency treeReading state informatio…...
wdcp搭建网站教程/软文营销的特点有哪些
月圆之夜在游泳池学习骑独角兽是不容易的,特别是对不会游泳的人。但是我知道可以依靠别人帮我浮起来。Kubernetes社区也是同样的热情和乐于助人,愿意帮助新手避免其淹没在无穷无尽的可能性中。准备好来实践了吗?请看下文。2017年12月的KubeCo…...
wordpress如何导入数据/营销管理系统
1、 搭建了mariadb galera集群后,整个集群停掉后如何启动呢,我们要先启动那个节点呢,今天我尝试把集群机器全部停掉,然后任意启动一个节点,发现报如下的错误: 170620 21:32:55 [ERROR] WSREP: It may not be safe to bootstrap the cluster from this node. It wa…...