【ESP32-S3】WINDOWS+VMware+ROS2+YDLIDA X2导航初步调试

【ESP32-S3】WINDOWS+VMware+ROS2+YDLIDA X2导航测试

      • 背景
      • 一、核心软硬件清单(适配Windows+VMware环境)
      • 二、详细实现步骤
        • [步骤1:VMware安装并配置Ubuntu 22.04(Windows宿主机)](#步骤1:VMware安装并配置Ubuntu 22.04(Windows宿主机))
          • [1.1 准备安装文件](#1.1 准备安装文件)
          • [1.2 创建并安装Ubuntu虚拟机](#1.2 创建并安装Ubuntu虚拟机)
          • [1.3 虚拟机后置配置(必做)](#1.3 虚拟机后置配置(必做))
        • [步骤2:Ubuntu虚拟机中搭建ROS2 Humble环境](#步骤2:Ubuntu虚拟机中搭建ROS2 Humble环境)
          • [2.1 安装ROS2 Humble核心包](#2.1 安装ROS2 Humble核心包)
          • [2.2 创建ROS2工作空间](#2.2 创建ROS2工作空间)
        • [步骤3:硬件连接与调试(重点解决VMware USB透传)](#步骤3:硬件连接与调试(重点解决VMware USB透传))
          • [3.1 YDLIDAR X2雷达调试(核心)](#3.1 YDLIDAR X2雷达调试(核心))
            • [3.1.1 串口透传配置](#3.1.1 串口透传配置)
            • [3.1.2 串口权限配置(避免访问被拒)](#3.1.2 串口权限配置(避免访问被拒))
            • [3.1.3 部署X2的ROS2驱动并测试](#3.1.3 部署X2的ROS2驱动并测试)
            • [3.1.4 测试雷达是否正常发布点云](#3.1.4 测试雷达是否正常发布点云)
          • [3.2 ESP32-S3与Ubuntu的通信配置](#3.2 ESP32-S3与Ubuntu的通信配置)
            • [3.2.1 ESP32端代码修改(核心:接收WiFi指令并控制电机)](#3.2.1 ESP32端代码修改(核心:接收WiFi指令并控制电机))
            • [3.2.2 Ubuntu端编写ROS2节点(发送速度指令到ESP32)](#3.2.2 Ubuntu端编写ROS2节点(发送速度指令到ESP32))
        • 步骤4:ROS2导航配置(核心)
          • [4.1 配置坐标系(TF变换)](#4.1 配置坐标系(TF变换))
          • [4.2 里程计发布(可选但推荐)](#4.2 里程计发布(可选但推荐))
          • [4.3 SLAM建图(生成环境地图)](#4.3 SLAM建图(生成环境地图))
          • [4.4 自主导航](#4.4 自主导航)
        • 步骤5:常见问题排查
      • 总结

背景

想在Windows电脑上通过VMware安装Linux系统,为基于ESP32-S3的电机小车(已支持HTML界面控制)集成YDLIDAR X2激光雷达,并基于ROS2实现小车的自主导航功能。这只是调试,因为雷达直接连接的电脑,测试一下ros2是否和esp32-s3进行通信

一、核心软硬件清单(适配Windows+VMware环境)

组件 作用 关键注意事项
Windows主机 运行VMware虚拟机 需开启虚拟化(BIOS中开启Intel VT-x/AMD-V)
VMware Workstation 安装Ubuntu系统 推荐16/17版本,支持USB 3.0透传
Ubuntu 22.04 LTS 运行ROS2、雷达驱动、导航算法 桌面版(新手友好),分配≥4G内存、≥40G硬盘
ESP32-S3开发板 小车电机控制+里程计数据采集 支持WiFi(和Ubuntu通信)/USB串口(备选)
YDLIDAR X2 激光点云采集 USB转串口,需透传到Ubuntu虚拟机
带编码器的直流电机 动力+里程计 导航必需(无编码器无法提供准确位姿)
电机驱动(DRV8833) 驱动电机 ESP32 GPIO控制
电源系统 供电 5V给ESP32/雷达,7-12V给电机驱动

二、详细实现步骤

步骤1:VMware安装并配置Ubuntu 22.04(Windows宿主机)

这一步是基础,重点解决虚拟机网络 和USB透传问题(导航依赖这两个功能)。

1.1 准备安装文件
  • 下载VMware Workstation Pro(官网下载试用版/破解版,推荐17.x);
  • 下载Ubuntu 22.04 LTS 桌面版镜像(官网链接,选择ubuntu-22.04.3-desktop-amd64.iso)。
1.2 创建并安装Ubuntu虚拟机
  1. 打开VMware,点击「创建新的虚拟机」→ 选择「典型」→ 下一步;
  2. 选择「安装程序光盘映像文件」,导入下载的Ubuntu ISO文件 → 下一步;
  3. 设置Ubuntu的用户名/密码(记住!)→ 下一步;
  4. 设置虚拟机名称和保存路径(建议非C盘)→ 下一步;
  5. 分配硬盘容量(≥40G,推荐60G),选择「将虚拟磁盘存储为单个文件」→ 下一步;
  6. 点击「自定义硬件」:
    • 内存:≥4G(推荐8G);
    • 处理器:≥2核;
    • 网络适配器:选择「桥接模式」(关键!让Ubuntu和ESP32在同一网段);
    • USB控制器:选择「USB 3.1」(支持雷达的USB串口);
  7. 完成硬件配置,点击「开启此虚拟机」,按提示安装Ubuntu(全程默认即可,等待10-20分钟)。
1.3 虚拟机后置配置(必做)
  1. 安装VMware Tools(解决分辨率/共享文件夹/鼠标无缝切换):

    • 点击VMware顶部「虚拟机」→ 「安装VMware Tools」;

    • Ubuntu中会出现VMware Tools光盘,复制里面的.tar.gz文件到桌面,解压后执行:

      bash 复制代码
      cd 解压后的文件夹
      sudo ./vmware-install.pl
    • 全程按回车默认,安装完成后重启虚拟机。

  2. 更新Ubuntu系统:

    bash 复制代码
    sudo apt update && sudo apt upgrade -y
步骤2:Ubuntu虚拟机中搭建ROS2 Humble环境

ROS2 Humble是Ubuntu 22.04的官方适配版本,稳定性最佳。

2.1 安装ROS2 Humble核心包
bash 复制代码
# 1. 配置系统环境(解决locale编码问题)
sudo locale-gen en_US en_US.UTF-8
sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8
export LANG=en_US.UTF-8

# 2. 添加ROS2软件源
sudo apt install -y curl gnupg2 lsb-release
sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null

# 3. 安装ROS2 Humble桌面版+导航全套包
sudo apt update && sudo apt install -y \
  ros-humble-desktop \
  ros-humble-navigation2 \
  ros-humble-nav2-bringup \
  ros-humble-slam-toolbox \
  ros-humble-tf2-tools \
  python3-colcon-common-extensions \
  python3-pyserial \
  ros-humble-teleop-twist-keyboard

# 4. 配置环境变量(永久生效)
echo "source /opt/ros/humble/setup.bash" >> ~/.bashrc
echo "source ~/ros2_ws/install/setup.bash" >> ~/.bashrc
echo "export ROS_DOMAIN_ID=0" >> ~/.bashrc  # 避免多设备通信冲突
source ~/.bashrc
2.2 创建ROS2工作空间
bash 复制代码
# 创建工作空间目录
mkdir -p ~/ros2_ws/src
cd ~/ros2_ws

# 初始化编译(空工作空间,生成配置文件)
colcon build --symlink-install
步骤3:硬件连接与调试(重点解决VMware USB透传)
3.1 YDLIDAR X2雷达调试(核心)
3.1.1 串口透传配置
  1. 将YDLIDAR X2的USB线插入Windows主机;

  2. 回到VMware,点击顶部「虚拟机」→「可移动设备」→ 找到「USB Serial Device」(X2的串口设备)→ 点击「连接」;

    • 若未识别,检查:① Windows是否安装了CH340驱动(X2的USB转串口芯片);② VMware USB控制器是否设为3.1;
  3. Ubuntu中验证串口是否识别:

    bash 复制代码
    ls /dev/ttyUSB*  # 正常会显示 /dev/ttyUSB0(或ttyACM0)
3.1.2 串口权限配置(避免访问被拒)
bash 复制代码
# 添加当前用户到dialout组(永久生效,需重启Ubuntu)
sudo usermod -aG dialout $USER
# 临时赋予串口权限(立即生效)
sudo chmod 777 /dev/ttyUSB0
3.1.3 部署X2的ROS2驱动并测试
bash 复制代码
# 克隆官方驱动到ROS2工作空间
cd ~/ros2_ws/src
git clone https://github.com/ydlidar/ydlidar_ros2_driver.git

# 编译驱动
cd ~/ros2_ws
colcon build --packages-select ydlidar_ros2_driver

# 修改雷达配置文件(匹配X2参数)
gedit ~/ros2_ws/src/ydlidar_ros2_driver/config/ydlidar_x2.yaml

将配置文件修改为以下内容(关键参数匹配X2):

yaml 复制代码
ydlidar_ros2_driver_node:
  ros__parameters:
    port: /dev/ttyUSB0        # 雷达串口(按实际修改)
    baudrate: 115200          # X2默认波特率
    frame_id: laser_link      # 雷达坐标系(后续导航要匹配)
    scan_frequency: 7         # X2最大10Hz,7Hz更稳定
    lidar_type: TYPE_X2       # 指定雷达型号
    device_type: TYPE_SERIAL  # 串口通信
    isSingleChannel: true     # X2是单通道
    inverted: false           # 雷达正装(反装则设为true)
    angle_max: 180.0          # X2最大扫描角度180°
    angle_min: -180.0
    range_max: 8.0            # 最大测距8米
    range_min: 0.1
    use_ros_time: false       # 不使用ROS时间
    enable_log: false         # 关闭日志(节省资源)
3.1.4 测试雷达是否正常发布点云
bash 复制代码
# 启动雷达驱动
ros2 launch ydlidar_ros2_driver ydlidar_launch.py

# 新开终端,查看点云话题(正常会显示数据)
ros2 topic echo /scan
  • 若报错「找不到串口」:重新透传USB设备,或检查串口名称(/dev/ttyACM0);
  • 若话题无数据:检查雷达供电(X2需稳定5V),或重启雷达。
3.2 ESP32-S3与Ubuntu的通信配置

原ESP32有HTML控制,现在需要新增「接收ROS2速度指令」的逻辑。新手推荐WiFi通信(避免串口占用):

3.2.1 ESP32端代码修改(核心:接收WiFi指令并控制电机)

使用Arduino IDE编写,核心逻辑:

  1. ESP32连接到和Ubuntu虚拟机同网段的WiFi(比如家里的路由器);
  2. 建立UDP/TCP服务器,接收Ubuntu发送的「前进/后退/左转/右转/停止」指令;
  3. 将指令转换为电机PWM信号,控制电机驱动模块。

示例代码(关键片段,需适配你的电机引脚):

cpp 复制代码
#include <WiFi.h>
#include <WiFiUdp.h>

// 1. WiFi配置(和Ubuntu同网段)
const char* ssid = "你的WiFi名称";
const char* password = "你的WiFi密码";
WiFiUDP udp;
unsigned int localPort = 8888;  // 本地UDP端口

// 2. 电机引脚配置(替换为你的实际引脚)
#define LEFT_MOTOR_PWM 10
#define LEFT_MOTOR_DIR 11
#define RIGHT_MOTOR_PWM 12
#define RIGHT_MOTOR_DIR 13

// 3. 速度参数
int linear_x = 0;   // 线速度(前进+,后退-,范围-100~100)
int angular_z = 0;  // 角速度(左转+,右转-,范围-50~50)

void setup() {
  Serial.begin(115200);
  
  // 初始化电机引脚
  pinMode(LEFT_MOTOR_PWM, OUTPUT);
  pinMode(LEFT_MOTOR_DIR, OUTPUT);
  pinMode(RIGHT_MOTOR_PWM, OUTPUT);
  pinMode(RIGHT_MOTOR_DIR, OUTPUT);
  
  // 连接WiFi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\nWiFi连接成功,IP地址:" + WiFi.localIP().toString());
  
  // 启动UDP
  udp.begin(localPort);
}

void loop() {
  // 接收UDP数据(来自Ubuntu的ROS2节点)
  int packetSize = udp.parsePacket();
  if (packetSize) {
    char cmd[100];
    int len = udp.read(cmd, sizeof(cmd));
    cmd[len] = '\0';
    Serial.print("收到指令:");
    Serial.println(cmd);
    
    // 解析指令(格式:linear_x,angular_z,比如"50,0"=前进,"0,30"=左转)
    sscanf(cmd, "%d,%d", &linear_x, &angular_z);
    controlMotor(linear_x, angular_z);
  }
}

// 电机控制函数(核心:将速度指令转为PWM)
void controlMotor(int linear, int angular) {
  // 计算左右轮速度(简易差速算法)
  int left_speed = linear - angular;
  int right_speed = linear + angular;
  
  // 限制速度范围(0~255)
  left_speed = constrain(left_speed, -100, 100);
  right_speed = constrain(right_speed, -100, 100);
  
  // 控制左轮方向和速度
  if (left_speed > 0) {
    digitalWrite(LEFT_MOTOR_DIR, HIGH);
    analogWrite(LEFT_MOTOR_PWM, map(left_speed, 0, 100, 0, 255));
  } else if (left_speed < 0) {
    digitalWrite(LEFT_MOTOR_DIR, LOW);
    analogWrite(LEFT_MOTOR_PWM, map(-left_speed, 0, 100, 0, 255));
  } else {
    analogWrite(LEFT_MOTOR_PWM, 0);
  }
  
  // 控制右轮方向和速度(逻辑同上)
  if (right_speed > 0) {
    digitalWrite(RIGHT_MOTOR_DIR, HIGH);
    analogWrite(RIGHT_MOTOR_PWM, map(right_speed, 0, 100, 0, 255));
  } else if (right_speed < 0) {
    digitalWrite(RIGHT_MOTOR_DIR, LOW);
    analogWrite(RIGHT_MOTOR_PWM, map(-right_speed, 0, 100, 0, 255));
  } else {
    analogWrite(RIGHT_MOTOR_PWM, 0);
  }
}
3.2.2 Ubuntu端编写ROS2节点(发送速度指令到ESP32)

在~/ros2_ws/src下创建功能包:

bash 复制代码
cd ~/ros2_ws/src
ros2 pkg create --build-type ament_python car_control --dependencies rclpy geometry_msgs

创建UDP发送节点~/ros2_ws/src/car_control/car_control/udp_publisher.py:

python 复制代码
#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
from geometry_msgs.msg import Twist
import socket

class CarControlNode(Node):
    def __init__(self):
        super().__init__('car_control_node')
        # 1. 订阅ROS2标准速度话题(/cmd_vel,导航模块会发布此话题)
        self.subscription = self.create_subscription(
            Twist,
            '/cmd_vel',
            self.cmd_vel_callback,
            10)
        
        # 2. 配置UDP(ESP32的IP和端口)
        self.esp32_ip = "192.168.1.100"  # 替换为ESP32的实际IP
        self.esp32_port = 8888
        self.udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        
        self.get_logger().info("小车控制节点已启动,目标ESP32 IP:{}".format(self.esp32_ip))

    def cmd_vel_callback(self, msg):
        # 解析Twist指令(ROS2标准:linear.x=线速度(m/s),angular.z=角速度(rad/s))
        # 转换为ESP32的指令范围(-100~100)
        linear_x = int(msg.linear.x * 100)  # 假设1m/s对应100的PWM值
        angular_z = int(msg.angular.z * 50) # 假设1rad/s对应50的角速度值
        
        # 发送指令到ESP32(格式:linear_x,angular_z)
        cmd = f"{linear_x},{angular_z}"
        self.udp_socket.sendto(cmd.encode(), (self.esp32_ip, self.esp32_port))
        self.get_logger().info(f"发送指令:{cmd}")

def main(args=None):
    rclpy.init(args=args)
    node = CarControlNode()
    rclpy.spin(node)
    node.destroy_node()
    rclpy.shutdown()

if __name__ == '__main__':
    main()

修改~/ros2_ws/src/car_control/setup.py(添加入口点):

python 复制代码
# 找到entry_points部分,添加:
entry_points={
    'console_scripts': [
        'udp_publisher = car_control.udp_publisher:main',
    ],
},

编译并测试:

bash 复制代码
cd ~/ros2_ws
colcon build --packages-select car_control

# 启动控制节点
ros2 run car_control udp_publisher

# 新开终端,发布速度指令(测试小车前进)
ros2 topic pub /cmd_vel geometry_msgs/msg/Twist "{linear: {x: 0.5, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}" --once
  • 若ESP32收到指令并控制电机,说明通信正常;
  • 若未收到:检查ESP32和Ubuntu的IP是否同网段,或关闭Ubuntu防火墙(sudo ufw disable)。
步骤4:ROS2导航配置(核心)

导航的核心是「激光点云+里程计+TF变换+导航算法」,新手推荐先做SLAM建图,再做自主导航。

4.1 配置坐标系(TF变换)

创建~/ros2_ws/src/car_control/launch/tf_launch.py(定义小车的坐标系关系):

python 复制代码
#!/usr/bin/env python3
import os
from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription
from launch_ros.actions import Node

def generate_launch_description():
    # 定义TF变换:laser_link(雷达)→ base_link(小车本体)→ base_footprint(地面)
    tf_node = Node(
        package='tf2_ros',
        executable='static_transform_publisher',
        arguments=['0.05', '0.0', '0.1', '0.0', '0.0', '0.0', 'base_link', 'laser_link'],
        # 参数说明:x y z roll pitch yaw 父坐标系 子坐标系
        # 需根据你的雷达安装位置调整(比如x=0.05表示雷达在小车前方5cm)
        name='laser_tf_publisher'
    )
    
    base_footprint_tf = Node(
        package='tf2_ros',
        executable='static_transform_publisher',
        arguments=['0.0', '0.0', '0.0', '0.0', '0.0', '0.0', 'base_footprint', 'base_link'],
        name='base_footprint_tf_publisher'
    )

    return LaunchDescription([
        tf_node,
        base_footprint_tf
    ])
4.2 里程计发布(可选但推荐)

若你的电机带编码器,在ESP32端读取编码器数据,通过UDP发送到Ubuntu,Ubuntu编写ROS2节点发布/odom话题(里程计),导航算法需要此数据做位姿估计。

4.3 SLAM建图(生成环境地图)
bash 复制代码
# 启动雷达+TF变换
ros2 launch ydlidar_ros2_driver ydlidar_launch.py
ros2 launch car_control tf_launch.py

# 新开终端,启动SLAM工具(激光建图)
ros2 launch slam_toolbox online_async_launch.py

# 新开终端,手动控制小车运动(建图)
ros2 run teleop_twist_keyboard teleop_twist_keyboard
  • 按键盘「w/s/a/d」控制小车移动,覆盖需要导航的区域;

  • 建图完成后,保存地图:

    bash 复制代码
    ros2 run nav2_map_server map_saver_cli -f ~/my_map
4.4 自主导航
bash 复制代码
# 启动雷达+TF变换+里程计(若有)
ros2 launch ydlidar_ros2_driver ydlidar_launch.py
ros2 launch car_control tf_launch.py
ros2 run car_control udp_publisher

# 启动导航模块(加载保存的地图)
ros2 launch nav2_bringup navigation_launch.py map:=~/my_map.yaml

# 新开终端,启动RViz(可视化导航)
ros2 launch nav2_bringup rviz_launch.py
  • 在RViz中:
    1. 点击「2D Pose Estimate」,在地图上标定小车当前位置;
    2. 点击「2D Goal Pose」,在地图上设置目标点;
    3. 小车会自动规划路径,避障并到达目标点。
步骤5:常见问题排查
  1. 雷达无数据:检查VMware USB透传、串口权限、雷达供电;
  2. 小车不响应ROS2指令:检查ESP32和Ubuntu的IP是否同网段、UDP端口是否匹配、电机引脚是否正确;
  3. 导航路径规划失败:检查TF变换是否正确、激光点云是否正常、里程计数据是否准确。

总结

  1. 环境核心:VMware需配置「桥接网络」和「USB 3.0透传」,确保Ubuntu能访问雷达和ESP32;
  2. 通信核心 :ESP32通过WiFi接收Ubuntu的UDP指令,Ubuntu订阅ROS2标准/cmd_vel话题并转发;
  3. 导航核心:先通过SLAM_toolbox生成地图,再用navigation2加载地图,通过RViz设置目标点实现自主导航。
相关推荐
UrSpecial7 分钟前
GPIO 是什么?
单片机·嵌入式硬件
lingchen190612 分钟前
Windows CMD 的 `cd`(change directory,切换目录)命令
windows·命令模式
ITHAOGE151 小时前
下载 | Win11 26H2 正式版发布!(ISO映像、2026年度版本、26300.9457、Windows 11)
windows·科技·微软·电脑
修船大队长2 小时前
配置接受报文每个报文对应一个mailbox配置流程记录
网络·单片机·mcu
YCOSA20253 小时前
雨晨 Windows 11 IoT 企业版 Edge 轻装 VCDX 29680.1000
windows·物联网
笨笨努力中4 小时前
2002年Windows XP系统下载视频资源迁移云盘
windows
搁浅小泽4 小时前
二极管选型技术规范
单片机·嵌入式硬件·汽车
搁浅小泽4 小时前
电感选型技术规范
单片机·嵌入式硬件·汽车
..Dauntless..5 小时前
【stm32】串口——在MCU内部的工作过程
stm32·单片机·嵌入式硬件
lzqrzpt5 小时前
临沂LED驱动电源工程选型标准与工艺对比解析
python·单片机·嵌入式硬件·物联网