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.信息分级方…...
工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...
OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...
听写流程自动化实践,轻量级教育辅助
随着智能教育工具的发展,越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式,也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建,…...
python报错No module named ‘tensorflow.keras‘
是由于不同版本的tensorflow下的keras所在的路径不同,结合所安装的tensorflow的目录结构修改from语句即可。 原语句: from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后: from tensorflow.python.keras.lay…...
【Go语言基础【13】】函数、闭包、方法
文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数(函数作为参数、返回值) 三、匿名函数与闭包1. 匿名函数(Lambda函…...
Go 并发编程基础:通道(Channel)的使用
在 Go 中,Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式,用于在多个 Goroutine 之间传递数据,从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...
关于easyexcel动态下拉选问题处理
前些日子突然碰到一个问题,说是客户的导入文件模版想支持部分导入内容的下拉选,于是我就找了easyexcel官网寻找解决方案,并没有找到合适的方案,没办法只能自己动手并分享出来,针对Java生成Excel下拉菜单时因选项过多导…...
实战三:开发网页端界面完成黑白视频转为彩色视频
一、需求描述 设计一个简单的视频上色应用,用户可以通过网页界面上传黑白视频,系统会自动将其转换为彩色视频。整个过程对用户来说非常简单直观,不需要了解技术细节。 效果图 二、实现思路 总体思路: 用户通过Gradio界面上…...
jdbc查询mysql数据库时,出现id顺序错误的情况
我在repository中的查询语句如下所示,即传入一个List<intager>的数据,返回这些id的问题列表。但是由于数据库查询时ID列表的顺序与预期不一致,会导致返回的id是从小到大排列的,但我不希望这样。 Query("SELECT NEW com…...
