将串口数据给进WSL再给进Docker——一次成功流水账(优化稿)
将串口数据给进WSL再给进Docker——一次成功流水账优化稿⚙️ 本文是一次实操记录把物理串口设备的数据先接入 Windows再转发进 WSL最后映射进 Docker 容器。以乐动单线激光雷达LD14P串口芯片 CH9102为例每一步都带验证。背景与整体思路平时主力是 Windows 电脑偶尔需要 Linux 环境。Win11 可以安装 WSL自带图形界面服务WSLg显示窗口没有问题进一步在 WSL 中配置 Docker就能直接在容器镜像里用 ROS 等工具。难点在于要同时读取串口数据——数据要穿过三层驱动Windows 串口驱动让 Windows 认到 USB 转串口设备COM 口。USB/IP 转发用usbipd把 USB 设备从 Windows 转发进 WSL。容器映射把 WSL 里的串口设备如/dev/ttyACM0映射进 Docker。下面按这三层顺序推进每一层都先配置、再验证。一、Windows 侧安装串口驱动并验证1.1 安装 Windows 串口驱动安装 CH9102 对应的 Windows 驱动CH343SERC:\Users\HongwuZhu\Downloads\激光雷达资料\串口驱动\CH9102\CH343SERCH9102的windows驱动\CH343SER\Driver1.2 确认 COM 口插入设备在设备管理器查看是否新增 COM 口。插入 USB 前插入 USB 后1.3 在 Windows 中测试雷达端口运行 CLI 测试脚本看是否有数据输出。如果有数据说明连接和 Windows 驱动都没问题cd D:\Project\turtlebot3_training\LD14P python ld14p_cli.py COM5如果有多个端口分别测试一下。有数据输出就说明 Windows 串口正常、雷达硬件没问题。 如果usbipd已经把 USB 设备独占转发给了 WSL此时要在 Windows 测试得先归还# PowerShell 管理员 usbipd detach --busid 1-4等几秒 Windows 会重新识别COM 口就回来了。测完再挂回去usbipd attach --busid 1-4 --wsl二、把 USB 设备转发给 WSLusbipdusbipd是一个基于 USB/IP 协议的服务端程序守护进程核心作用是把一台电脑上连接的物理 USB 设备通过网络共享给其他系统使用——这里就是共享给 WSL。2.1 查看设备的 BUSID# (base) PS C:\Users\HongwuZhu usbipd list Connected: BUSID VID:PID DEVICE STATE 1-4 1a86:55d4 USB-Enhanced-SERIAL CH9102 (COM3) Not shared由此得到对应的BUSID 1-4。1a86:55d4是设备的 VID:PID厂商号/产品号在不同系统中不会变化。如果状态已是Shared直接在 WSL 中重新触发一下即可。说明设备管理器里看到的是 COM 口而usbipd list里不显示 COM——这是正常的。COM 端口号对usbipd转发完全没有影响它走的是 USB 总线不经过 COM 端口。核心数据 BUSID1-4、VID:PID1a86:55d4 都对就说明设备被正确识别了。2.2 绑定并挂载到 WSL# 假设 BUSID 是 1-4绑定并转发到 WSL usbipd bind --busid 1-4 --force usbipd attach --busid 1-4 --wslusbipd bind --busid 1-4 --force将主机上指定总线ID1-4的USB设备强制绑定到usbipd服务使其可以被后续重定向。usbipd attach --busid 1-4 --wsl将已绑定的USB设备挂载到WSL中让WSL能够像使用本地设备一样访问该串口。三、在 WSL 中验证 USB 接口进入 WSL 后能否认到设备取决于加载了哪个驱动。下面两种情况按优先级尝试。情况一推荐本例成功cdc-acm 直接认到 CH9102只加载cdc-acm不去碰ch341让内核自动匹配# 只加载 cdc-acm不要 echo new_id让内核自动匹配 sudo modprobe cdc-acm # 看看设备是否已自动绑定 dmesg | tail -10 ls -la /dev/ttyACM* /dev/ttyUSB* 2/dev/nullcdc-acm是 Linux 内核的 USB 串口驱动模块负责将符合 CDC ACM 协议如 Arduino、3G 模块、部分 FTDI 设备的 USB 设备映射为/dev/ttyACM*虚拟串口让用户空间程序像操作普通串口一样读写。如果cdc-acm认到了 CH9102会出现/dev/ttyACM0这就是最理想的情况。测试sudo chmod 666 /dev/ttyACM0 cd /mnt/d/Project/turtlebot3_training/LD14P python3 ld14p_win_wsl_cli.py /dev/ttyACM0看到数据流就说明 WSL 中雷达完全正常了。情况二给 ch341-uart 打补丁new_id如果走的是ch341驱动需要手动把设备的 VID:PID 喂给ch341-uart让它接管echo 1a86 55d4 | sudo tee /sys/bus/usb-serial/drivers/ch341-uart/new_id sudo chmod 666 /dev/ttyUSB0 /dev/ttyUSB1 cd /mnt/d/Project/turtlebot3_training/LD14P python3 ld14p_cli.py /dev/ttyUSB0这条命令的作用是强制让 Linux 内核的ch341-uart驱动去识别并接管一个它默认不支持的 USB 转串口设备——相当于给驱动打补丁让系统把设备认作串口如/dev/ttyUSB0以识别市面上那些非标准 PID 的 CH341 芯片。ch341-uart是 Linux 内核里用于支持 CH341/CH340 系列 USB‑串口转换芯片的内核驱动模块.ko文件。它包含在主线内核的drivers/usb/serial/ch341.c中属于“USB 串口转换器驱动”的子系统。当插入 CH341 芯片的 USB 串口线时系统会自动加载这个内核模块生成/dev/ttyUSB0等设备节点。tee指令是一个 Linux/Unix 命令作用是从标准输入读取数据并同时将数据写入一个或多个文件以及输出到标准输出通常是终端。典型的用法是command | tee output.txt这样command的输出既会显示在屏幕上也会被保存到output.txt。常用于需要同时“看一眼结果”和“留一份记录”的场景。⚠️ 局限ch341驱动对 CH9102不完全兼容。常见症状是/dev/ttyUSB0能打开但收到 0 帧数据换/dev/ttyUSB1则直接 I/O 错误。遇到这种情况说明这条路走不通优先回到情况一用cdc-acm。情况三安装 Linux 专用串口驱动源码编译编译厂商提供的 Linux 驱动源码。有尝试这个方法但是在make的时候报错感觉很难解决常见排查步骤在 WSL 里执行uname -r获取内核版本然后安装对应的头文件sudo apt install linux-headers-$(uname -r)。检查驱动源码里的Makefile是否硬编码了内核路径若用KERNELDIR变量需确认它指向/lib/modules/$(uname -r)/build。如果源码是针对较老内核如 4.x写的而 WSL 是 5.10可能需要手动修改Kconfig或补丁或者考虑在 Docker 容器里编译但要保证容器内核与 WSL 一致。实在无法编译的替代方案如果只是需要串口 USB 转接如 CH340、CP2102WSL 内通常已自带ch341、cp210x等内核模块无需额外编译。检查lsmod | grep usb是否已加载。如果lsmod | grep usb的输出中已经包含ch341、cp210x等模块那么插上对应的 USB 串口设备后WSL 内核会自动加载驱动并创建/dev/ttyUSB0或类似名称节点你可以直接通过该设备名访问。如果模块未加载先确认模块名例如ch341或cp210x然后手动加载sudomodprobe ch341# 若为 CH340/CH341 芯片sudomodprobe cp210x# 若为 CP2102 芯片加载后再次运行lsmod | grep usb确认再插拔设备即可。若提示modprobe: FATAL: Module not found说明 WSL 内核未包含该模块此时需要重新编译带有该驱动模块的内核参考 WSL 自定义内核文档但一般常见模块都已内置。cdc-acm与ch341/cp210x是不同类别的USB串口驱动不是“一起”的cdc-acm是 Linux 内核内置的通用驱动遵循 USB CDC ACM 协议常用于 Arduino Uno、STM32 虚拟串口、某些 FTDI 芯片等设备。ch341和cp210x是特定芯片CH340/CH341、CP2102的专用驱动属于内核中的独立模块不归入 cdc-acm 体系。你的设备应由芯片决定加载哪个模块CH341 芯片 →ch341CP2102 →cp210x若设备是 CDC ACM 兼容 →cdc-acm。原文只列出了 CH341 和 CP210x 的加载命令因为它们常见且用户可能主动需要。cdc-acm通常已内置在 WSL 内核中无需手动modprobe所以原文未提及。若要确认可用lsmod | grep acm查看是否已自动加载。流程是usbipd 在 Windows 侧将 USB 设备打包成 TCP 数据流WSL 内核的 usbip-host 模块负责解包并重新模拟出一个 USB 设备。这个“模拟出的设备”对 WSL 内核而言就是一块新挂载的 USB 硬件和物理插入 U 盘没有区别——因此 WSL 内核仍然需要对应设备的 Linux 驱动例如ch341、cp210x、ftdi_sio等串口驱动才能识别设备并创建/dev/ttyUSB0节点。如果 WSL 默认内核已包含该驱动大多数常见 USB 串口芯片都已内置为模块或编译进内核那就无需自己编译但如果遇到厂商独有、内核未收录的驱动你仍然需要编译内核模块并加载。四、启动 Docker把串口映射进容器4.1 先检查设备权限在 WSL 中ls -la /dev/ttyACM0 # 应显示: crw-rw---- 1 root dialout 166, 0 ... /dev/ttyACM0 # 如果是 crw------- 没有 dialout 组需要: sudo chmod 666 /dev/ttyACM04.2 启动容器方式 A用封装脚本推荐bash docker_run_wsl.sh --port /dev/ttyACM0 -e--port /dev/ttyACM0指定要映射进容器的串口设备已确认在 WSL 中是ttyACM0。-e脚本里写的 enter 参数启动后直接进入容器命令行。方式 B直接用原始docker run命令适用于 Win11 WSLg 环境直接复制整行到 WSL 终端粘贴在docker run命令的--name tb3_training后面或任意-v之前的位置插入--device/dev/ttyACM0:/dev/ttyACM0即可dockerrm-ftb3_training2/dev/null;dockerrun-it-d--nametb3_training--device/dev/ttyACM0:/dev/ttyACM0--networkhost-eDISPLAY:0-eLIBGL_ALWAYS_SOFTWARE1-eTURTLEBOT3_MODELburger-v/tmp/.X11-unix:/tmp/.X11-unix-v/mnt/wslg:/mnt/wslg-v/mnt/d/Project/turtlebot3_training:/workspace-w/workspace tb3-training:latestbash如果串口设备名不固定如ttyACM1、ttyUSB0可将/dev/ttyACM0替换为实际路径也可用--privileged映射全部设备不推荐安全性低--privileged -v /dev:/dev。若串口在 WSL 中已通过usbipd挂载且显示为/dev/ttyACM0上述命令即可在容器内通过/dev/ttyACM0访问。五、重开终端后如何重新进入环境关闭所有终端后想重新进入 Docker 环境按容器状态分两种情况。5.1 容器仍在运行最常见容器第一次启动后通常一直在后台运行只需两步# [PowerShell] 第一步进入 WSLwsl# [WSL] 第二步进入容器dockerexec-ittb3_trainingbash进入后提示符变为root...:/workspace#即可正常使用ros2、python等命令。 小技巧可以开多个 PowerShell 窗口每个都执行上面两步实现多终端同时操作同一个容器。5.2 容器已停止如电脑重启后Docker Desktop 会自动启动但容器需手动拉起# [WSL] 先启动容器再进入dockerstart tb3_trainingdockerexec-ittb3_trainingbash若Docker 容器启动时配置了设备映射--device /dev/ttyACM0但USB 串口设备未插入或未挂载到 WSL。docker start tb3_training会提示无法启动。WSL 默认不自动挂载 Windows 的 COM 端口需要手动通过usbipd-win或wsl --mount的方式将物理串口映射到 WSL 的/dev/ttyACM0。解决步骤若设备已连接使用usbipd attach将 USB 设备绑定到 WSL需安装 usbipd-win参考 官方文档。若不想挂载物理设备可临时修改容器配置移除--device参数若容器已停止你需要不加载 USB 设备重新启动容器保留其他挂载/参数。同样容器 ID 不许重复创建可先docker start试试——如果原容器是docker run -d --device/dev/ttyUSB0 ...启动的现在设备不存在docker start会失败设备不存在。此时应创建一个新容器不绑定 --device比如dockerrun-it--rm\--namemy_container_no_usb\-v/some/path:/some/path\your_imagebash若想修改已有容器的配置不重新创建Docker 不支持运行时变更--device参数。你只能 commit 镜像后基于新镜像创建新容器或直接创建新容器推荐。5.3 常用容器管理命令dockerexec-ittb3_trainingbash# 进入容器dockerstop tb3_training# 停止容器dockerstart tb3_training# 启动容器dockerrm-ftb3_training# 强制删除容器六、常见问题现象原因解决/dev/ttyACM0报permission denied容器内用户无访问权限在 WSL 执行sudo chmod 666 /dev/ttyACM0容器内找不到/dev/ttyACM0USB 未挂载到 WSL回到 PowerShell 执行usbipd attach --busid 1-4 --wsl