亚博microros小车-原生ubuntu支持系列:20 ROS Robot APP建图
依赖工程
新建工程laserscan_to_point_publisher
src/laserscan_to_point_publisher/laserscan_to_point_publisher/目录下新建文件laserscan_to_point_publish.py
#!/usr/bin/env python3import rclpy
from rclpy.node import Node
from geometry_msgs.msg import PoseStamped, TransformStamped
from nav_msgs.msg import Path
from sensor_msgs.msg import LaserScan
import tf2_ros
import mathclass laserscanToPointPublish(Node):def __init__(self):super().__init__('robot_pose_publisher')self.subscription = self.create_subscription(LaserScan,'/scan',self.laserscan_callback,10)self.sacn_point_publisher = self.create_publisher(Path,'/scan_points',10)def laserscan_callback(self, msg):
# print(msg)angle_min = msg.angle_minangle_increment = msg.angle_incrementlaserscan = msg.ranges# 获取激光雷达数据
# print(laserscan)laser_points = self.laserscan_to_points(laserscan, angle_increment, angle_increment) self.sacn_point_publisher.publish(laser_points)def laserscan_to_points(self, laserscan, angle_min, angle_increment):points = []angle = angle_minlaser_points = Path()for distance in laserscan:x = distance * math.cos(angle + 135)#获取当前激光雷达数据点的的坐标值y = distance * math.sin(angle + 135)pose = PoseStamped()pose.pose.position.x = xpose.pose.position.y = ypoints.append(pose)angle += angle_incrementlaser_points.poses = pointsreturn laser_pointsdef main(args=None):rclpy.init(args=args)robot_laser_scan_publisher = laserscanToPointPublish()rclpy.spin(robot_laser_scan_publisher)robot_pose_publisher.destroy_node()rclpy.shutdown()if __name__ == '__main__':main()
robot_pose_publisher_ros2
src/robot_pose_publisher_ros2/src/目录下新建robot_pose_publisher.cpp
/*!* \file robot_pose_publisher.cpp* \brief Publishes the robot's position in a geometry_msgs/Pose message.** Publishes the robot's position in a geometry_msgs/Pose message based on the TF* difference between /map and /base_link.** \author Milan - milan.madathiparambil@gmail.com* \date April 20 1020*/#include <chrono>
#include <memory>#include "rclcpp/rclcpp.hpp"
#include "geometry_msgs/msg/pose_stamped.hpp"
#include "geometry_msgs/msg/pose.hpp"
#include "geometry_msgs/msg/transform_stamped.hpp"
#include "tf2_ros/transform_listener.h"
#include "tf2_ros/buffer.h"using namespace std::chrono_literals;/* This example creates a subclass of Node and uses std::bind() to register a* member function as a callback from the timer. */class RobotPosePublisher : public rclcpp::Node
{
public:RobotPosePublisher() : Node("robot_pose_publisher"){tf_buffer_ = std::make_shared<tf2_ros::Buffer>(this->get_clock());tf_listener_ = std::make_shared<tf2_ros::TransformListener>(*tf_buffer_);this->declare_parameter<std::string>("map_frame","map");this->declare_parameter<std::string>("base_frame","base_link");this->declare_parameter<bool>("is_stamped",false);this->get_parameter("map_frame", map_frame);this->get_parameter("base_frame", base_frame);this->get_parameter("is_stamped", is_stamped);if (is_stamped)publisher_stamp = this->create_publisher<geometry_msgs::msg::PoseStamped>("robot_pose", 1);elsepublisher_ = this->create_publisher<geometry_msgs::msg::Pose>("robot_pose", 1);timer_ = this->create_wall_timer(50ms, std::bind(&RobotPosePublisher::timer_callback, this));}private:void timer_callback(){geometry_msgs::msg::TransformStamped transformStamped;try{transformStamped = tf_buffer_->lookupTransform(map_frame, base_frame,this->now());}catch (tf2::TransformException &ex){return;}geometry_msgs::msg::PoseStamped pose_stamped;pose_stamped.header.frame_id = map_frame;pose_stamped.header.stamp = this->now();pose_stamped.pose.orientation.x = transformStamped.transform.rotation.x;pose_stamped.pose.orientation.y = transformStamped.transform.rotation.y;pose_stamped.pose.orientation.z = transformStamped.transform.rotation.z;pose_stamped.pose.orientation.w = transformStamped.transform.rotation.w;pose_stamped.pose.position.x = transformStamped.transform.translation.x;pose_stamped.pose.position.y = transformStamped.transform.translation.y;pose_stamped.pose.position.z = transformStamped.transform.translation.z;if (is_stamped)publisher_stamp->publish(pose_stamped);elsepublisher_->publish(pose_stamped.pose);}rclcpp::TimerBase::SharedPtr timer_;rclcpp::Publisher<geometry_msgs::msg::PoseStamped>::SharedPtr publisher_stamp;rclcpp::Publisher<geometry_msgs::msg::Pose>::SharedPtr publisher_;size_t count_;bool is_stamped = false;std::string base_frame = "base_link";std::string map_frame = "map";std::shared_ptr<tf2_ros::TransformListener> tf_listener_;std::shared_ptr<tf2_ros::Buffer> tf_buffer_;
};int main(int argc, char *argv[])
{rclcpp::init(argc, argv);rclcpp::spin(std::make_shared<RobotPosePublisher>());rclcpp::shutdown();return 0;
}
其中获取结果 buffer_.lookup_transform 获取map到base_link的坐标变化, 再发布robot_pose。
rosbridge_server
这个没有安装也需要安装下。
启动脚本
src/yahboomcar_nav/launch/map_cartographer_app_launch.xml
<launch><include file="$(find-pkg-share rosbridge_server)/launch/rosbridge_websocket_launch.xml"/><node name="laserscan_to_point_publisher" pkg="laserscan_to_point_publisher" exec="laserscan_to_point_publisher"/><include file="$(find-pkg-share yahboomcar_nav)/launch/map_cartographer_launch.py"/><include file="$(find-pkg-share robot_pose_publisher_ros2)/launch/robot_pose_publisher_launch.py"/><include file="$(find-pkg-share yahboom_app_save_map)/yahboom_app_save_map.launch.py"/>
</launch>
这里运行了以下几个launch文件和节点Node:
-
rosbridge_websocket_launch.xml:开启rosbridge服务相关节点,启动后,可以通过网络连接到ROS
-
laserscan_to_point_publisher:把雷达的点云转换发布到APP上进行可视化
-
map_cartographer_launch.py:cartographer建图程序
-
robot_pose_publisher_launch.py:小车位姿发布程序,小车位姿在APP进行可视化
-
yahboom_app_save_map.launch.py:保存地图的程序
程序功能说明
小车连接上代理,运行程序,打开手机上下载的【ROS Robot】app,输入小车的IP地址,选择ROS2,点击连接,即可连接上小车。通过滑动界面的轮盘可以控制小车,缓慢控制小车走完建图的区域,最后点击保存地图,小车会保存当前建好的地图。
启动
#小车代理
sudo docker run -it --rm -v /dev:/dev -v /dev/shm:/dev/shm --privileged --net=host microros/micro-ros-agent:humble udp4 --port 8090 -v4
#摄像头代理(先启动代理再打开小车开关)
docker run -it --rm -v /dev:/dev -v /dev/shm:/dev/shm --privileged --net=host microros/micro-ros-agent:humble udp4 --port 9999 -v4
首先启动小车处理底层数据程序,终端输入,
ros2 launch yahboomcar_bringup yahboomcar_bringup_launch.py
启动APP建图命令,终端输入,
ros2 launch yahboomcar_nav map_cartographer_app_launch.xml
#启动ESP32 摄像头
ros2 run yahboom_esp32_camera sub_img
手机APP显示如下图,输入小车的IP地址,【zh】表示中文,【en】表示英文;选择ROS2,下边的Video Tpoic选择/usb_cam/image_raw/compressed,最后点击【连接】

这个ip就是小车的配置ip。成功连接上后,跑一点地图显示如下,

有个问题就是app上不显示摄像头画面。我看亚博官网的文章上也没有显示,不知道为啥,猜测是控制小车的ip跟摄像头代理的不是1个。
另外的感受这个比较难操控小车,速度太快了,不如键盘好掌握。
以上。
相关文章:
亚博microros小车-原生ubuntu支持系列:20 ROS Robot APP建图
依赖工程 新建工程laserscan_to_point_publisher src/laserscan_to_point_publisher/laserscan_to_point_publisher/目录下新建文件laserscan_to_point_publish.py #!/usr/bin/env python3import rclpy from rclpy.node import Node from geometry_msgs.msg import PoseStam…...
计算机毕业设计Python+Vue.js游戏推荐系统 Steam游戏推荐系统 Django Flask 游 戏可视化 游戏数据分析 游戏大数据 爬虫
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...
Qt最新热点
Qt的最新热点主要集中在以下几个方面: 跨平台开发:Qt继续强调其在跨平台开发方面的优势,支持在Windows、macOS、Linux以及移动操作系统(如Android和iOS)上的应用开发。 Qt for Python:Qt for Python(PySide2和PySide6)的发展,为Python开发者提供了更强大的工具来创建桌…...
k8sollama部署deepseek-R1模型,内网无坑
这是目录 linux下载ollama模型文件下载到本地,打包迁移到k8s等无网络环境使用下载打包ollama镜像非k8s环境使用k8s部署访问方式非ollama运行deepseek模型linux下载ollama 下载后可存放其他服务器 curl -L https://ollama.com/download/ollama-linux-amd64.tgz -o ollama-linu…...
音频录制一般在什么情况下会选择保存为PCM?什么情况会选择保存为WAV?
在音频开发中,选择保存为 PCM 或 WAV 格式取决于具体的应用场景和需求。以下是两种格式的特点以及适用场景的分析: PCM 格式 特点: 原始音频数据: PCM 是未压缩的原始音频数据,没有任何文件头或元数据。数据直接以二进制形式存储,通常是采样点的值。文件体积较大: 由于…...
【Elasticsearch】nested聚合
在 Elasticsearch 中,嵌套聚合(nestedaggregation)的语法形式用于对嵌套字段(nestedfields)进行聚合操作。嵌套字段是 Elasticsearch 中的一种特殊字段类型,用于存储数组中的对象,这些对象需要独…...
从零创建 Vue 3 项目
Vue 3 作为当前最流行的前端框架之一,提供了多种创建项目的方式。本文将详细介绍七种常见的创建 Vue 3 项目的方法,涵盖从本地开发到在线编辑器的多种场景,帮助您选择最适合的方式 快速创建 Vue 3项目 进行开发。 方法一:使用 Vue…...
Day48_20250130【回校继续打卡】_单调栈part1_739.每日温度|496.下一个更大元素I|503.下一个更大元素II
Day48_20250130_单调栈part1_739.每日温度|496.下一个更大元素I|503.下一个更大元素II 20250130补完 739.每日温度 题目 给定一个整数数组 temperatures ,表示每天的温度,返回一个数组 answer ,其中 answer[i] 是指对于第 i 天࿰…...
spy-debugger + Charles 调试移动端/内嵌小程序H5
简介说明: PC端可以用F12进行console等进行调试,但移动端App中使用webview就无法进行实时调试,针对这种情况 1. 安装 全局安装 spy-debugger sudo npm install spy-debugger -g // window不用加sudo2. spy-debugger 证书 其实spy-debugg…...
【NLP 20、Encoding编码 和 Embedding嵌入】
目录 一、核心定义与区别 二、常见Encoding编码 (1) 独热编码(One-Hot Encoding) (2) 位置编码(Positional Encoding) (3) 标签编码(Label Encoding) (4) 注意事项 三、常见Embedding词嵌入 (1) 基础词嵌入…...
【LeetCode 刷题】二叉树(3)-二叉树的属性
此博客为《代码随想录》二叉树章节的学习笔记,主要内容为二叉树的属性相关的题目解析。 文章目录 101. 对称二叉树104.二叉树的最大深度111.二叉树的最小深度222.完全二叉树的节点个数110.平衡二叉树257. 二叉树的所有路径404.左叶子之和513.找树左下角的值112. 路…...
深度学习模型可视化小工具wandb
1 概述 Wandb(Weights & Biases,网址是https://wandb.ai)是一个用于机器学习项目实验跟踪、可视化和管理的工具,旨在用户更有效地监控模型训练过程、优化性能,并分享和复现实验结果。对于使用者而言ÿ…...
数据库系统概论的第六版与第五版的区别,附pdf
我用夸克网盘分享了「数据库系统概论第五六版资源」,点击链接即可保存。 链接:https://pan.quark.cn/s/21a278378dee 第6版教材修订的主要内容 为了保持科学性、先进性和实用性,在第5版教材基础上对全书内容进行了修改、更新和充实。 在科…...
【Kubernetes Pod间通信-第2篇】使用BGP实现Pod到Pod的通信
Kubernetes中Pod间的通信 本系列文章共3篇: 【Kubernetes Pod间通信-第1篇】在单个子网中使用underlay网络实现Pod到Pod的通信【Kubernetes Pod间通信-第2篇】使用BGP实现Pod到Pod的通信(本文介绍)【Kubernetes Pod间通信-第3篇】Kubernetes中Pod与ClusterIP服务之间的通信…...
python:csv文件批量导入mysql
1.导入sql文件到数据库中 mysql -u username -p要先创建一个空的数据库 CREATE DATABASE your_database_name;USE your_database_name;导入sql文件 source /path/to/your/file.sql;查看某个表格的结构,为后续数据插入做准备 DESCRIBE table_name;2.插入假数据到对应…...
软件设计模式
目录 一.创建型模式 抽象工厂 Abstract Factory 构建器 Builder 工厂方法 Factory Method 原型 Prototype 单例模式 Singleton 二.结构型模式 适配器模式 Adapter 桥接模式 Bridge 组合模式 Composite 装饰者模式 Decorator 外观模式 Facade 享元模式 Flyw…...
C++证件识别接口-身份证识别-护照识别-驾驶证识别-户口页识别
数字化信息时代,快速准确地处理各类证件信息已经成为许多行业提升效率的关键。无论是金融、物流、旅游还是公共服务领域,证件识别接口的应用极大的简化了证件信息提取的流程,提高了录入效率。 证件识别接口提升业务处理效率 传统的人工审核…...
3步打造C# API安全密盾
引言:API 安全的重要性 在数字化浪潮中,应用程序编程接口(API)已成为不同软件系统之间通信和数据交互的关键桥梁。无论是企业内部的微服务架构,还是面向外部用户的在线服务,API 都承担着数据传输和业务逻辑…...
vscode 如何通过Continue引入AI 助手deepseek
第一步: 在deepseek 官网上注册账号,得到APIKeys(deepseek官网地址) 创建属于自己的APIKey,然后复制这个key,(注意保存自己的key)! 第二步: 打开vscode,在插件市场安装Continue插件, 点击设置,添加deepseek模型,默认…...
通过docker安装部署deepseek以及python实现
前提条件 Docker 安装:确保你的系统已经安装并正确配置了 Docker。可以通过运行 docker --version 来验证 Docker 是否安装成功。 网络环境:保证设备有稳定的网络连接,以便拉取 Docker 镜像和模型文件。 步骤一:拉取 Ollama Docker 镜像 Ollama 可以帮助我们更方便地管理…...
iOS 音频录制、播放与格式转换
iOS 音频录制、播放与格式转换:基于 AVFoundation 和 FFmpegKit 的实现 在 iOS 开发中,音频处理是一个非常常见的需求,比如录音、播放音频、音频格式转换等。本文将详细解读一段基于 AVFoundation 和 FFmpegKit 的代码,展示如何实现音频录制、播放以及 PCM 和 AAC 格式之间…...
RK3576——USB3.2 OTG无法识别到USB设备
问题:使用硬盘接入到OTG接口无热插拔信息,接入DP显示屏无法正常识别到显示设备,但是能通过RKDdevTool工具烧录系统。 问题分析:由于热插拔功能实现是靠HUSB311芯片完成的,因此需要先确保HUSB311芯片驱动正常工作。 1. …...
【MySQL】语言连接
语言连接 一、下载二、mysql_get_client_info1、函数2、介绍3、示例 三、其他函数1、mysql_init2、mysql_real_connect3、mysql_query4、mysql_store_result5、mysql_free_result6、mysql_num_fields7、mysql_num_rows8、mysql_fetch_fields9、mysql_fetch_row10、mysql_close …...
20240206 adb 连不上手机解决办法
Step 1: lsusb 确认电脑 usb 端口能识别设备 lsusb不知道设备有没有连上,就插拔一下,对比观察多了/少了哪个设备。 Step 2: 重启 adb server sudo adb kill-serversudo adb start-serveradb devices基本上就可以了~ Reference https://b…...
何为运行时(Runtime)
Runtime(运行时) 是计算机程序中实际执行的阶段,指从程序启动到终止的整个运行过程。它涵盖了程序运行所需的环境、资源管理和底层支持机制。 1. 核心概念 运行时环境(Runtime Environment) 程序运行依赖的基础设施&am…...
基于ansible部署elk集群
ansible部署 ELK部署 ELK常见架构 (1)ElasticsearchLogstashKibana:这种架构是最常见的一种,也是最简单的一种架构,这种架构通过Logstash收集日志,运用Elasticsearch分析日志,最后通过Kibana中…...
【C语言设计模式学习笔记1】面向接口编程/简单工厂模式/多态
面向接口编程可以提供更高级的抽象,实现的时候,外部不需要知道内部的具体实现,最简单的是使用简单工厂模式来进行实现,比如一个Sensor具有多种表示形式,这时候可以在给Sensor结构体添加一个enum类型的type,…...
Mac上搭建k8s环境——Minikube
1、在mac上安装Minikube可执行程序 brew cask install minikub 安装后使用minikube version命令查看版本 2、安装docker环境 brew install --cask --appdir/Applications docker #安装docker open -a Docker #启动docker 3、安装kubectl curl -LO https://storage.g…...
Github - 记录一次对“不小心包含了密码的PR”的修复
Github - 记录一次对“不小心包含了密码的PR”的修复 前言 和好朋友一起开发一个字节跳动青训营抖音电商后端(now private)的项目,某大佬不小心把本地一密码commit上去并提了PR。 PR一旦发出则无法被删除,且其包含的commit也能被所有能看到这个仓库的…...
【创建模式-单例模式(Singleton Pattern)】
赐萧瑀 实现方案饿汉模式懒汉式(非线程安全)懒汉模式(线程安全)双重检查锁定静态内部类 攻击方式序列化攻击反射攻击 枚举(最佳实践)枚举是一种类 唐 李世民 疾风知劲草,板荡识诚臣。 勇夫安识义,智者必怀仁…...
