当前位置: 首页 > 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.信息分级方…...

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…...

【Python】 -- 趣味代码 - 小恐龙游戏

文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...

利用ngx_stream_return_module构建简易 TCP/UDP 响应网关

一、模块概述 ngx_stream_return_module 提供了一个极简的指令&#xff1a; return <value>;在收到客户端连接后&#xff0c;立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量&#xff08;如 $time_iso8601、$remote_addr 等&#xff09;&a…...

循环冗余码校验CRC码 算法步骤+详细实例计算

通信过程&#xff1a;&#xff08;白话解释&#xff09; 我们将原始待发送的消息称为 M M M&#xff0c;依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)&#xff08;意思就是 G &#xff08; x ) G&#xff08;x) G&#xff08;x) 是已知的&#xff09;&#xff0…...

Java多线程实现之Callable接口深度解析

Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...

ETLCloud可能遇到的问题有哪些?常见坑位解析

数据集成平台ETLCloud&#xff0c;主要用于支持数据的抽取&#xff08;Extract&#xff09;、转换&#xff08;Transform&#xff09;和加载&#xff08;Load&#xff09;过程。提供了一个简洁直观的界面&#xff0c;以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...

C# 类和继承(抽象类)

抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...

Spring AI 入门:Java 开发者的生成式 AI 实践之路

一、Spring AI 简介 在人工智能技术快速迭代的今天&#xff0c;Spring AI 作为 Spring 生态系统的新生力量&#xff0c;正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务&#xff08;如 OpenAI、Anthropic&#xff09;的无缝对接&…...

Element Plus 表单(el-form)中关于正整数输入的校验规则

目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入&#xff08;联动&#xff09;2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...