ROS2开发机器人移动

news2024/11/26 8:32:11

.创建功能包和节点
这里我们设计两个节点

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1875379.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【升压电子烟方案】DC-DC电源升压恒压芯片FP6277+全极低功耗霍尔MH251在电子烟中的应用

电子烟是一种新型烟草制品&#xff0c;由于其健康、环保和口感多样化的特点&#xff0c;逐渐受到了消费者的青睐。 升压芯片作为电子烟的核心组件之一&#xff0c;主要作用是将输入的电压升高至合适的工作电压&#xff0c;霍尔传感器控制电子烟的使用状态&#xff0c;以确保电子…

【笔记】Spring Cloud Gateway 实现 gRPC 代理

Spring Cloud Gateway 在 3.1.x 版本中增加了针对 gRPC 的网关代理功能支持,本片文章描述一下如何实现相关支持.本文主要基于 Spring Cloud Gateway 的 官方文档 进行一个实践练习。有兴趣的可以翻看官方文档。 由于 Grpc 是基于 HTTP2 协议进行传输的&#xff0c;因此 Srping …

已解决java.security.acl.LastOwnerException:无法移除最后一个所有者的正确解决方法,亲测有效!!!

已解决java.security.acl.LastOwnerException&#xff1a;无法移除最后一个所有者的正确解决方法&#xff0c;亲测有效&#xff01;&#xff01;&#xff01; 目录 问题分析 出现问题的场景 报错原因 解决思路 解决方法 1. 检查当前所有者数量 2. 添加新的所有者 3. 维…

【Python系列】Python 中循环依赖问题及其解决方案

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

CAN和CANFD数据写入.asc文件的dll

因为工作需要&#xff0c;需要做一些硬件不是CANoe的上位机&#xff08;比如说周立功CAN,NI-CAN&#xff09;&#xff0c;上位机需要有记录数据的功能&#xff0c;所以用Qt制作了一个记录数据的dll&#xff0c;方便重复使用&#xff08;因为有的客户指定了编程软件&#xff0c;…

Spring框架整体概念

Spring框架基础概念 首先&#xff0c; 从Spring框架的整体架构和组成对整体框架有个认知。 Spring基础 - Spring和Spring框架组成 上图是从官网4.2.x获取的原图&#xff0c;目前我们使用最广法的版本应该都是5.x&#xff0c;5版本移除了Web模块中的Portlet子模块&#xff0c;新…

机器人控制系列教程之控制理论概述

经典控制理论 经典控制理论主要研究线性定常系统。所谓线性控制系统是指系统中各组成环节或元件的状态由线性微分方程描述的控制系统。如果描述该线性系统的微分方程系数是常数,则称为线性定常系统。描述自动控制系统输入量、输出量和内部量之间关系的数学表达式称为系统的数学…

STM32第七课:KQM6600空气质量传感器

文章目录 需求一、KQM6600模块及接线方法二、模块配置流程1.环境2.配置时钟和IO3.配置串口初始化&#xff0c;使能以及中断4.中断函数 三、数据处理四、关键代码总结 需求 能够在串口实时显示当前的VOC&#xff08;挥发性有机化合物&#xff09;&#xff0c;甲醛和Co2浓度。 …

GPU算力是什么,哪些行业需要用到GPU算力?

近两年&#xff0c;计算能力已成为推动各行各业发展的关键因素。而GPU&#xff08;图形处理器&#xff09;算力&#xff0c;作为现代计算技术的重要分支&#xff0c;正逐渐在多个领域展现出其强大的潜力和价值。尚云将简要介绍GPU算力的定义和基本原理&#xff0c;并探讨其在哪…

使用Apache POI库在Java中导出Excel文件的详细步骤

使用Apache POI库在Java中导出Excel文件的详细步骤 学习总结 1、掌握 JAVA入门到进阶知识(持续写作中……&#xff09; 2、学会Oracle数据库入门到入土用法(创作中……&#xff09; 3、手把手教你开发炫酷的vbs脚本制作(完善中……&#xff09; 4、牛逼哄哄的 IDEA编程利器技…

企业中对RAG的优化方案

企业中对RAG的优化方案 RAG优化&#xff1a;检索、语义和生成方面的提升RAG流程一、数据处理优化数据清洗实际案例 二、检索方面优化向量库检索倒排索引数据库检索 三、生成方面优化调整Prompt 四、架构优化RAGAgent架构Self-RAG架构Agentic RAG架构 总结 RAG优化&#xff1a;检…

【Django】网上蛋糕项目商城-热销和新品

概念 本文将完成实现项目的热销和新品两个分类的商品列表进行分页展示。 热销和新品功能实现步骤 在head.html头部页面中点击这两个超链接向服务器发送请求。 在urls.py文件中定义该请求地址 path(goodsrecommend_list/,views.goodsrecommend_list) 在views.py文件中定义g…

mac配置hdc

首先需要找到 .zshrc 文件&#xff1a; 访达进入到user文件夹中&#xff0c;shiftcommand.键显示隐藏文件&#xff1a; 双击打开进行编辑&#xff0c;在最后添加 //HDC_HOME 指的是hdc的绝对路径&#xff0c;要替换成自己的路径 export HDC_HOME/Users/你的名字/Library/Huaw…

系统架构设计师 - 计算机网络(1)

计算机网络 计算机网络TCP/IP 协议簇TCP与UDP ★★★DHCP与DNS ★★★DNS 协议应用DHCP 协议应用 网络规划与设计逻辑设计与物理设计 ★★★★逻辑网络设计物理网路设计 层次化网络设计网络冗余设计 网络存储 ★★网络存储方式磁盘阵列 - Raid 大家好呀&#xff01;我是小笙&am…

二刷算法训练营Day45 | 动态规划(7/17)

目录 详细布置&#xff1a; 1. 139. 单词拆分 2. 多重背包理论基础 3. 背包总结 3.1 背包递推公式 3.2 遍历顺序 01背包 完全背包 详细布置&#xff1a; 1. 139. 单词拆分 给你一个字符串 s 和一个字符串列表 wordDict 作为字典。如果可以利用字典中出现的一个或多个单…

北大西洋横断面(ANT)项目计划

North Atlantic Transect (ANT) program 简介 - **&#x1f5fa;️ 北大西洋横断面计划 (ANT) 概述** 北大西洋横断面计划 (ANT) 是一个由美国资助的 GEOTRACES 项目&#xff0c;旨在测量非洲海岸沿线的海洋化学参数。该计划收集了有关海水中的溶解氧、营养盐、碳酸盐离子、微…

STM32第八课:Su-03t语音识别模块

文章目录 需求一、SU03T语音识别模块二、模块配置流程1.固件烧录2.配置串口和传输引脚3.中断函数4.double类型转换5 数据发送6.接收处理 三、该模块完整代码总结 需求 基于上次完成空气质量传感器&#xff0c;利用SU03T语音识别模块&#xff0c;实现空气质量的语音问答播报。 …

240622_昇思学习打卡-Day4-ResNet50迁移学习

240622_昇思学习打卡-Day4-ResNet50迁移学习 我们对事物的认知都是一点一点积累出来的&#xff0c;往往借助已经认识过的东西&#xff0c;可以更好地理解和认识新的有关联的东西。比如一个人会骑自行车&#xff0c;我们让他去骑摩托车他也很快就能学会&#xff0c;比如已经学会…

STM32开发方式的演变与未来展望

一、STM32开发方式的演变 自2007年STM32微控制器首次亮相以来&#xff0c;其开发方式经历了从寄存器到标准库&#xff0c;再到HAL&#xff08;硬件抽象层&#xff09;的演变。 1.寄存器开发&#xff08;2007年-2010年代初&#xff09; 最初&#xff0c;由于初期缺乏足够的软…

Cyuyanzhong的内存函数

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、memcpy函数的使用与模拟实现二、memmove函数的使用和模拟实现三、memset函数与memcmp函数的使用&#xff08;一&#xff09;、memset函数&#xff08;内存块…