当前位置: 首页 > news >正文

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&#xff0c;机器人节点&#xff0c;对外提供控制机器人移动服务并发布机器人的状态。 example_interfaces_control_01&#xff0c;控制节点&#xff0c;发送机器人移动请求&#xff0c;订阅机器人状态话题…...

【强化学习】第02期:动态规划方法

笔者近期上了国科大周晓飞老师《强化学习及其应用》课程&#xff0c;计划整理一个强化学习系列笔记。笔记中所引用的内容部分出自周老师的课程PPT。笔记中如有不到之处&#xff0c;敬请批评指正。 文章目录 2.1 动态规划&#xff1a;策略收敛法/策略迭代法2.2 动态规划&#xf…...

安全技术和防火墙(二)

接上一节 备份和还原 iptables-save > /opt/iptables.bak iptables-restore < /opt/iptables.bak snat和dnat snat源地址转换 内网到外网 内网ip转换成可以访问外网的ip 内网的多个主机可以只有一个有效的公网ip地址访问外部网络 dnat 目的地址转发 外部用户&#…...

【51单片机入门】数码管原理

文章目录 前言共阴极与共阳极数码管多个数码管显示原理 总结 前言 在我们的日常生活中&#xff0c;数码管被广泛应用于各种电子设备中&#xff0c;如电子表、计时器、电子钟等。数码管的主要功能是显示数字和一些特殊字符。在这篇文章中&#xff0c;我们将探讨数码管的工作原理…...

三星DRAM、NAND,“又双叒叕”带头涨价了

据韩国媒体《每日经济新闻》报道&#xff0c;三星电子计划在第三季度上调服务器DRAM和企业级NAND闪存的价格&#xff0c;涨幅预计在15%-20%&#xff0c;主要受人工智能(AI)需求激增的推动。这一举措有望提振公司下半年业绩。 据《经济日报》报道援引业内消息&#xff0c;由于厂…...

星戈瑞FITC-PEG2000-Biotin的生物相容性

生物相容性是指材料与生物体之间相互作用时&#xff0c;材料对生物体无毒、无刺激&#xff0c;且能够被生物体接受并正常发挥其功能的特性。 FITC-PEG2000-Biotin作为一种荧光标记试剂&#xff0c;在细胞成像、药物传递和生物标志物检测等领域具有诸多应用前景。 FITC-PEG2000…...

数据资产管理的艺术:构建智能化、精细化的数据资产管理体系,从数据整合、分析到决策支持,为企业提供一站式的数据资产解决方案,助力企业把握数字时代的新机遇

一、引言 在数字化浪潮席卷全球的今天&#xff0c;数据已经成为企业最重要的资产之一。如何高效、安全地管理这些海量数据&#xff0c;从中提取有价值的信息&#xff0c;并将其转化为决策支持&#xff0c;是每个企业都必须面对的挑战。本文将探讨数据资产管理的艺术&#xff0…...

基于Java微信小程序校园自助打印系统设计和实现(源码+LW+调试文档+讲解等)

&#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN作者、博客专家、全栈领域优质创作者&#xff0c;博客之星、平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌&#x1f497; &#x1f31f;文末获取源码数据库&#x1f31f;感兴趣的可以先收藏起来&#xff0c;还…...

股票复盘思路

股票复盘是一个回顾和分析市场及个人交易决策的过程,旨在从过去的表现中学习并优化未来的投资策略。以下是一些基本的股票复盘步骤和关注点: 市场概况回顾: 观察并记录每日市场的整体表现,包括大盘指数涨跌、成交量变化。统计涨停和跌停个股的数量,了解市场情绪和活跃度。…...

OpenGL系列(六)摄像机

在 OpenGL系列&#xff08;六&#xff09;变换 中&#xff0c;一个目标物体经过模型矩阵、观察矩阵和投影矩阵的变换才能正常显示出来&#xff0c;其中模型矩阵主要针对目标物体&#xff0c;它会影响物体的位姿。观察矩阵和投影矩阵主要针对观察者而已&#xff0c;这两个变换决…...

一个端口配置两个vue和后端服务,nginx以及前后端服务怎么配?

nginx配置重点看server中的内容&#xff1a; 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&#xff08;Optical Character Recognition&#xff0c;光学字符识别&#xff09;系统。其技术体系包括文字检测、文字识别、文本方向检测和图像处理等模块。以下是其优点&#xff1a; 高精度&#xff1a;PaddleOCR采用深度学习算法进行训练…...

webpack【实用教程】

基础配置 配置的拆分和合并 通常 webpack 的配置文件会有3个 webpack.common.js 公共配置&#xff08;会被另外两个配置文件导入并合并&#xff09;webpack.dev.js 开发环境的配置webpack.prod.js 生产环境的配置 开发环境的本地服务 在 webpack.dev.js 中配置 devServer:…...

如何使用C++进行文件读写操作

在C中&#xff0c;我们可以使用标准库中的 <fstream>&#xff08;文件流&#xff09;来进行文件的读写操作。以下是一些基本的文件读写操作的示例。 读取文件 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)

试过重点放在独立游戏上&#xff0c;有个indienova独立游戏团队是全职的&#xff0c;由于他们干了几个月&#xff0c;节奏暂时跟不上&#xff0c;紧张焦虑了。五一时也有点自暴自弃了&#xff0c;实在没必要&#xff0c;按照自己的节奏走即可。精力和时间也有限&#xff0c;放在…...

LeetCode.面试题17.24.最大子矩阵详解

问题描述 给定一个正整数、负整数和 0 组成的 N M 矩阵&#xff0c;编写代码找出元素总和最大的子矩阵。 返回一个数组 [r1, c1, r2, c2]&#xff0c;其中 r1, c1 分别代表子矩阵左上角的行号和列号&#xff0c;r2, c2 分别代表右下角的行号和列号。若有多个满足条件的子矩阵…...

云动态摘要 2024-06-28

给您带来云厂商的最新动态&#xff0c;最新产品资讯和最新优惠更新。 最新优惠与活动 [新客专享]WeData 限时特惠 腾讯云 2024-06-21 数据分类分级管理&#xff0c;构建数据安全屏障 &#xff0c;仅需9.9元&#xff01; 云服务器ECS试用产品续用 阿里云 2024-04-14 云服务器…...

六、资产安全—信息分级资产管理与隐私保护(CISSP)

目录 1.信息分级 2.信息分级方法 3.责任的层级 4.资产管理 5.隐私数据管理角色 6.数据安全控制 7.数据保护方案 8.使用安全基线 六、资产安全—数据管理(CISSP): 五、身份与访问管理—身份管理和访问控制管理(CISSP): 1.信息分级 信息分级举列: 2.信息分级方…...

Python|GIF 解析与构建(5):手搓截屏和帧率控制

目录 Python&#xff5c;GIF 解析与构建&#xff08;5&#xff09;&#xff1a;手搓截屏和帧率控制 一、引言 二、技术实现&#xff1a;手搓截屏模块 2.1 核心原理 2.2 代码解析&#xff1a;ScreenshotData类 2.2.1 截图函数&#xff1a;capture_screen 三、技术实现&…...

地震勘探——干扰波识别、井中地震时距曲线特点

目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波&#xff1a;可以用来解决所提出的地质任务的波&#xff1b;干扰波&#xff1a;所有妨碍辨认、追踪有效波的其他波。 地震勘探中&#xff0c;有效波和干扰波是相对的。例如&#xff0c;在反射波…...

C++实现分布式网络通信框架RPC(3)--rpc调用端

目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中&#xff0c;我们已经大致实现了rpc服务端的各项功能代…...

ubuntu搭建nfs服务centos挂载访问

在Ubuntu上设置NFS服务器 在Ubuntu上&#xff0c;你可以使用apt包管理器来安装NFS服务器。打开终端并运行&#xff1a; sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享&#xff0c;例如/shared&#xff1a; sudo mkdir /shared sud…...

2021-03-15 iview一些问题

1.iview 在使用tree组件时&#xff0c;发现没有set类的方法&#xff0c;只有get&#xff0c;那么要改变tree值&#xff0c;只能遍历treeData&#xff0c;递归修改treeData的checked&#xff0c;发现无法更改&#xff0c;原因在于check模式下&#xff0c;子元素的勾选状态跟父节…...

ServerTrust 并非唯一

NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...

【HTTP三个基础问题】

面试官您好&#xff01;HTTP是超文本传输协议&#xff0c;是互联网上客户端和服务器之间传输超文本数据&#xff08;比如文字、图片、音频、视频等&#xff09;的核心协议&#xff0c;当前互联网应用最广泛的版本是HTTP1.1&#xff0c;它基于经典的C/S模型&#xff0c;也就是客…...

如何在最短时间内提升打ctf(web)的水平?

刚刚刷完2遍 bugku 的 web 题&#xff0c;前来答题。 每个人对刷题理解是不同&#xff0c;有的人是看了writeup就等于刷了&#xff0c;有的人是收藏了writeup就等于刷了&#xff0c;有的人是跟着writeup做了一遍就等于刷了&#xff0c;还有的人是独立思考做了一遍就等于刷了。…...

Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)

Aspose.PDF 限制绕过方案&#xff1a;Java 字节码技术实战分享&#xff08;仅供学习&#xff09; 一、Aspose.PDF 简介二、说明&#xff08;⚠️仅供学习与研究使用&#xff09;三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...

Caliper 负载(Workload)详细解析

Caliper 负载(Workload)详细解析 负载(Workload)是 Caliper 性能测试的核心部分,它定义了测试期间要执行的具体合约调用行为和交易模式。下面我将全面深入地讲解负载的各个方面。 一、负载模块基本结构 一个典型的负载模块(如 workload.js)包含以下基本结构: use strict;/…...