尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

基于Docker的ROS2 Humble Jetson Nano开发环境部署与GPU加速实践

基于Docker的ROS2 Humble Jetson Nano开发环境部署与GPU加速实践 简介Docker容器技术通过封装应用及其依赖实现了环境隔离与一致性部署其核心原理是利用操作系统级虚拟化。在机器人操作系统ROS开发中环境配置复杂、依赖冲突是常见痛点尤其在Jetson Nano这类ARM架构边缘设备上。通过Docker容器化开发者能快速获得可复现、可移植的标准化开发环境极大提升团队协作与持续集成效率。在嵌入式AI与机器人领域结合NVIDIA GPU硬件加速容器化方案能确保视觉处理、SLAM等算法稳定调用CUDA与cuDNN库实现从开发到部署的全流程一致性。本文聚焦于为Jetson Nano设备提供开箱即用的ROS2 Humble Docker镜像详解其集成ROS2 Humble、CUDA支持与常用生态工具的技术实现并演示如何通过容器化工作流进行机器人感知节点的快速开发与多机部署。1. 项目概述与核心价值如果你正在用Jetson Nano搞ROS2机器人开发大概率经历过这样的场景好不容易在Ubuntu上装好了ROS2 Humble结果发现某个关键的依赖包版本不对或者系统更新后ROS2环境直接崩了。更别提当你需要在多台Jetson Nano上部署完全一致的环境时那种重复劳动和配置差异带来的调试噩梦。这个项目就是为了终结这一切而生的。它提供了一个基于ROS2 Humble版本专为NVIDIA Jetson NanoARM64架构打造的Docker容器化开发与部署环境镜像。简单说这就是一个“开箱即用”的完整ROS2机器人开发沙箱你只需要一条docker run命令就能获得一个纯净、统一、可复现的开发环境无论是算法验证、多机部署还是团队协作效率都能直接拉满。这个镜像的核心价值在于“一致性”和“可移植性”。在嵌入式AI开发中环境配置往往是最大的非技术性障碍。Jetson Nano虽然性能强大但其ARM架构和有限的存储空间使得从源码编译ROS2及其生态包如Navigation2、MoveIt2变得异常耗时且容易出错。这个预构建的Docker镜像将所有这些繁琐的步骤提前固化包含了ROS2 Humble桌面版、常用的构建工具colcon、通信库并针对Jetson的GPU进行了CUDA和cuDNN的适配确保ROS2节点能够直接调用NVIDIA的硬件加速资源。对于个人开发者它能让你快速跳过环境搭建直接进入核心算法开发对于团队和产品化部署它则是保证从开发到测试再到生产环境行为一致的基石。2. 镜像核心内容与技术栈解析这个镜像不是一个简单的ROS2运行时而是一个功能完备的开发与轻量级部署底座。我们来拆解一下它的技术栈和预装内容理解为什么这样设计。2.1 基础操作系统与ROS2发行版选择镜像的基础操作系统选择了Ubuntu 22.04 Jammy Jellyfish。这是经过深思熟虑的首先ROS2 Humble Hawksbill的官方支持系统就是Ubuntu 22.04这意味着最广泛的软件包兼容性和最稳定的官方更新源。其次Ubuntu 22.04 LTS长期支持版本能提供长达5年的安全更新这对于需要长期维护的机器人项目至关重要。最后NVIDIA为Jetson系列提供的SDK Manager和JetPack SDK其Linux驱动和CUDA工具链也优先保证了对Ubuntu LTS版本的支持。在这个Ubuntu 22.04基础上我们集成了ROS2 Humble Hawksbill桌面版ros-humble-desktop。选择桌面版而非基础版是因为它包含了RViz2、rqt等至关重要的可视化调试工具。在机器人开发中能实时看到传感器数据、机器人模型和导航路径其调试效率是命令行无法比拟的。虽然这会增加一些镜像体积但对于开发环境而言这笔“空间税”交得值。2.2 针对Jetson Nano的硬件加速适配这是本镜像区别于普通x86_64平台ROS2 Docker镜像的关键。Jetson Nano的核心优势在于其集成的NVIDIA Maxwell架构GPU。为了让ROS2中的视觉处理如OpenCV图像处理、SLAM如VSLAM算法甚至一些机器学习推理节点能充分利用这块GPU镜像内必须集成正确的驱动和计算库。NVIDIA Container Toolkit集成这是让Docker容器能够访问宿主机GPU的桥梁。镜像内预装了nvidia-container-toolkit并正确配置了容器运行时。这确保了你在运行容器时通过--gpus all参数容器内的应用就能像在宿主机上一样通过nvidia-smi命令查看GPU状态并调用CUDA API。CUDA与cuDNN运行时环境镜像基于NVIDIA官方为Jetson平台提供的容器基础镜像如nvcr.io/nvidia/l4t-base:r32.7.1或类似版本构建这意味着它已经包含了与Jetson Nano JetPack版本匹配的CUDA和cuDNN库。例如针对JetPack 4.6通常会包含CUDA 10.2。这为在ROS2节点中直接进行GPU加速计算提供了底层支持。OpenCV with CUDA SupportROS2的cv_bridge和image_transport等包严重依赖OpenCV。我们预编译或安装了支持CUDA后端的OpenCV版本。这意味着当你使用image_proc节点处理图像或者自己编写一个使用OpenCV的节点时像cvtColor、resize、GaussianBlur这样的操作可能会被自动卸载到GPU上执行显著提升图像流水线的处理速度。2.3 开发工具链与常用生态包一个高效的开发环境离不开顺手的工具。镜像内预置了以下关键工具构建系统colcon是ROS2推荐的构建工具替代了ROS1的catkin_make。我们安装了colcon及其常用插件如colcon-common-extensions。包管理rosdep用于自动安装工作空间所需的外部系统依赖。通信测试工具ros2cli命令行工具套件是必备的。同时为了便于调试可能还预装了ros2bag用于话题录制与回放、ros2 launch用于启动复杂系统的相关支持。常用ROS2包虽然桌面版包含了很多基础包但针对机器人开发我们可能还会预装一些高频使用的包例如navigation2(Nav2)用于移动机器人导航的完整解决方案。turtlebot3相关的包作为经典的学习和快速原型平台。slam_toolbox一个流行的SLAM实现。rviz2和rqt的各类插件。注意预装过多的特定功能包会导致镜像臃肿且可能不符合所有用户的需求。因此一个更优雅的设计是提供一个“基础开发镜像”然后通过Dockerfile的多阶段构建或使用rosdep在用户自己的src工作空间内按需安装。本项目镜像更可能采用前者即提供一个干净、带基础工具和硬件支持的“底座”。2.4 网络与通信优化配置ROS2基于DDS数据分发服务进行通信而DDS对网络有多播和端口有特定要求。在Docker容器内运行ROS2需要妥善处理网络模式。Host网络模式最简单的方式是使用--networkhost运行容器。这样容器与宿主机共享网络命名空间ROS2节点发现的通信与宿主机上运行无异非常适合单机开发调试。Bridge网络模式与多机通信在需要容器隔离或组成多容器应用时会使用桥接网络。这时需要确保ROS2使用的DDS中间件如Fast DDS或Cyclone DDS的多播流量能在容器间正确路由。镜像内可能会预配置环境变量如ROS_DOMAIN_ID、FASTRTPS_DEFAULT_PROFILES_FILE来帮助在复杂网络环境下建立通信。ROS_DOMAIN_ID这是一个非常重要的隔离机制。通过设置不同的ROS_DOMAIN_ID0-232可以在同一物理网络内隔离不同的ROS2网络避免设备间误通信。镜像的启动脚本或文档会强调这一点。3. 镜像获取、运行与基础使用实操理论说了这么多现在我们来实际操作看看如何把这个镜像用起来。3.1 获取镜像的两种途径通常项目会提供两种获取方式从Docker Hub拉取推荐如果作者已将构建好的镜像推送到了Docker Hub等公共仓库这是最快捷的方式。假设镜像名为your-username/ros2-humble-jetson-nano:latest。# 在Jetson Nano上执行 sudo docker pull your-username/ros2-humble-jetson-nano:latest这种方式省去了本地构建数小时的编译时间。你需要确认该镜像标签与你的JetPack版本匹配。本地构建如果项目提供了Dockerfile你可以从源码构建这样能确保完全可控或适配自定义修改。# 克隆项目仓库假设在GitHub上 git clone https://github.com/your-username/ros2-jetson-nano-docker.git cd ros2-jetson-nano-docker # 构建镜像这将在Jetson Nano上执行非常耗时 sudo docker build -t ros2-humble-jetson-nano:custom .实操心得在Jetson Nano上构建大型Docker镜像尤其是需要从源码编译ROS2可能耗时数小时且对SD卡寿命是考验。建议在构建时将Docker的存储目录挂载到外部USB 3.0 SSD硬盘上并确保Nano供电充足最好使用桶形电源而非Micro USB。3.2 启动容器并进入开发环境获取镜像后使用以下命令启动一个交互式容器sudo docker run -it --rm \ --networkhost \ --privileged \ --gpus all \ -v /dev:/dev \ -v /tmp/.X11-unix:/tmp/.X11-unix \ -e DISPLAY$DISPLAY \ -v $HOME/ros2_ws:/home/ros/ros2_ws \ --name ros2_humble_dev \ your-username/ros2-humble-jetson-nano:latest \ /bin/bash参数逐行解析-it交互式终端。--rm容器退出后自动删除避免积累无用容器。--networkhost使用主机网络简化ROS2节点发现。--privileged赋予容器几乎所有的宿主机设备访问权限。这对于访问某些传感器如USB摄像头、雷达是必要的但存在安全风险仅限开发环境。--gpus all关键将宿主机的GPU资源透传给容器。-v /dev:/dev将宿主机的设备目录挂载到容器使容器能访问串口、USB设备等。-v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY$DISPLAY这两项配合允许容器内启动GUI应用如RViz2、rqt并将窗口显示到宿主机的屏幕上。前提是宿主机本身已启动图形界面。-v $HOME/ros2_ws:/home/ros/ros2_ws这是最重要的挂载。将宿主机上的一个目录~/ros2_ws挂载到容器内用户的工作空间。这样你在容器内编写的所有代码、创建的包都实际保存在宿主机上容器销毁后代码也不会丢失。/home/ros是容器内预设的普通用户目录。--name给容器起个名字方便管理。最后指定镜像和启动命令/bin/bash。执行后你将进入容器内的bash终端。首先可以验证基础环境# 检查ROS2版本 ros2 --version # 检查CUDA和GPU nvidia-smi # 启动一个简单的演示节点 ros2 run demo_nodes_cpp talker在另一个终端宿主机或另一个容器用ros2 run demo_nodes_cpp listener应该能接收到消息。3.3 在容器内进行ROS2开发工作流现在你可以在挂载的/home/ros/ros2_ws目录下开始标准的ROS2开发创建工作空间与源码cd /home/ros/ros2_ws mkdir -p src cd src # 这里可以git clone你的代码或者用ros2 pkg create创建新包 ros2 pkg create --build-type ament_cmake my_robot_package --dependencies rclcpp std_msgs安装依赖与构建cd /home/ros/ros2_ws # 安装系统依赖如果需要 rosdep install -i --from-path src --rosdistro humble -y # 使用colcon构建 colcon build --symlink-install # 激活当前工作空间的环境 source install/setup.bash运行与调试编写节点代码后构建并运行。你可以使用ros2 run也可以编写launch文件用ros2 launch启动多个节点。RViz2和rqt等工具可以直接在容器内启动窗口会显示在宿主机上。4. 高级应用场景与镜像定制基础使用只是开始这个镜像的真正威力体现在以下高级场景中。4.1 多机/多容器ROS2系统部署在真实的机器人系统中可能将不同功能的节点部署在不同的容器甚至不同的机器上。单机多容器你可以为导航、感知、控制分别启动不同的容器每个容器只运行特定的节点组。它们通过--networkhost共享主机网络或者通过自定义的Docker网络进行桥接。关键是要为所有容器设置相同的ROS_DOMAIN_ID环境变量例如-e ROS_DOMAIN_ID42并确保DDS配置允许跨容器发现。多机部署在多台Jetson Nano组成的集群中每台机器都运行着这个镜像的容器。你需要确保所有机器在同一个局域网内并设置相同的ROS_DOMAIN_ID和正确的多播路由。有时需要配置DDS中间件如FastRTPS的XML配置文件指定发现服务器或禁用多播改用单播地址列表以应对复杂的网络环境。4.2 与宿主机IDE的集成开发你不需要在容器内使用文本编辑器写代码。更高效的方式是在宿主机上用你喜欢的IDE如VSCode打开挂载的~/ros2_ws目录进行编码。VSCode远程开发安装VSCode的“Remote - Containers”扩展。然后在项目根目录~/ros2_ws创建.devcontainer/devcontainer.json配置文件指定使用本项目镜像。这样VSCode可以直接将整个开发环境“注入”到容器中你在宿主机VSCode里写的代码、运行的终端、调试的程序实际都在容器环境内执行获得无缝体验。CLI开发对于习惯命令行的人来说在宿主机编辑代码在容器终端里执行构建和运行命令这种分离式工作流也非常清晰。4.3 镜像的个性化定制与分层构建你很可能需要在这个基础镜像上安装额外的软件包。最佳实践是编写你自己的Dockerfile以这个镜像作为基础镜像FROM。# 使用本项目镜像作为基础 FROM your-username/ros2-humble-jetson-nano:latest # 切换到有sudo权限的root用户进行系统安装 USER root # 安装你需要的额外系统包例如特定版本的Python库、工具 RUN apt-get update apt-get install -y \ python3-pip \ libserial-dev \ rm -rf /var/lib/apt/lists/* RUN pip3 install --no-cache-dir pyserial transforms3d # 切换回容器内默认的非root用户通常是ros USER ros # 设置工作空间如果基础镜像没有 WORKDIR /home/ros/ros2_ws然后构建你自己的衍生镜像。这种分层构建的方式既保留了基础镜像的稳定性又满足了项目的特殊需求。4.4 生成轻量级部署镜像开发镜像通常包含编译工具、头文件等体积较大。对于最终的产品部署我们需要一个只包含可执行文件、库文件和运行时的“瘦身”镜像。这可以通过Dockerfile的多阶段构建来实现# 第一阶段构建阶段使用完整的开发镜像 FROM your-username/ros2-humble-jetson-nano:latest AS builder WORKDIR /home/ros/ros2_ws COPY ./src ./src RUN rosdep install -i --from-path src --rosdistro humble -y RUN colcon build --symlink-install --cmake-args -DCMAKE_BUILD_TYPERelease # 第二阶段运行阶段使用一个更小的基础镜像如runtime版本 FROM nvcr.io/nvidia/l4t-base:r32.7.1 AS runtime # 安装ROS2 Humble的最小运行时和依赖 RUN apt-get update apt-get install -y \ ros-humble-ros-base \ # 其他必要的运行时库如OpenCV、CUDA运行时 rm -rf /var/lib/apt/lists/* # 从构建阶段拷贝安装好的工件 COPY --frombuilder /home/ros/ros2_ws/install /opt/robot_app # 设置环境变量指向我们的应用 ENV AMENT_PREFIX_PATH/opt/robot_app ENV COLCON_PREFIX_PATH/opt/robot_app ENV LD_LIBRARY_PATH/opt/robot_app/lib:$LD_LIBRARY_PATH ENV PATH/opt/robot_app/bin:$PATH # 设置容器启动命令例如启动你的主节点 CMD [ros2, launch, my_robot_package, robot_bringup.launch.py]这样构建出的最终镜像体积会小很多更适合部署到生产环境的Jetson Nano上。5. 常见问题、故障排查与优化技巧在实际使用中你肯定会遇到各种问题。这里记录了一些典型场景和解决方法。5.1 容器启动与GPU相关问题问题现象可能原因排查与解决步骤运行容器时报错docker: Error response from daemon: could not select device driver...NVIDIA Container Toolkit未安装或未正确配置。1. 在宿主机执行 dpkg -l容器内执行nvidia-smi命令报错或显示No devices found1. 启动容器时未加--gpus all参数。2. 宿主机NVIDIA驱动异常。1. 检查docker run命令是否包含--gpus all。2. 在宿主机执行nvidia-smi确保驱动正常。Jetson Nano需通过JetPack刷机确保驱动完好。RViz2或GPU加速的节点在容器内运行非常卡顿可能是图形渲染未使用硬件加速。1. 确保启动命令有-v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY。2. 尝试在宿主机设置xhost local:docker允许容器连接X11。3. 对于更复杂的3D渲染考虑使用NVIDIA的--runtimenvidia旧版或确保容器内有合适的OpenGL库。5.2 ROS2通信与网络问题问题现象可能原因排查与解决步骤容器内节点无法与宿主机或其他容器内的节点通信1. 网络模式不正确。2. ROS_DOMAIN_ID不匹配。3. 防火墙/多播被阻。1. 单机开发优先使用--networkhost。2. 检查所有终端/容器的echo $ROS_DOMAIN_ID是否一致。3. 使用ros2 topic list和ros2 node list查看可见性。多机通信失败1. 网络路由问题多播包无法跨子网。2. 各机器时钟不同步。1. 配置DDS使用单播发现。对于Fast DDS设置环境变量FASTRTPS_DEFAULT_PROFILES_FILE指向一个配置了initialPeersList的XML文件。2. 使用chrony或ntp同步所有机器时间。ros2 topic echo收不到数据但ros2 topic list能看到话题DDS的QoS服务质量策略不匹配。检查发布者和订阅者的QoS配置可靠性、持久性、历史深度。默认通常是兼容的但自定义节点时容易出错。使用ros2 topic info -v topic_name查看详情。5.3 性能与资源优化Jetson Nano资源有限需要精打细算。存储空间优化使用SSD强烈建议将Docker的根目录/var/lib/docker迁移到外接的USB 3.0 SSD上。Jetson Nano的eMMC或SD卡读写慢且频繁的镜像操作易导致损坏。清理Docker定期清理无用的镜像、容器和构建缓存。sudo docker system prune -a sudo docker volume prune内存与交换空间运行ROS2 RViz2可能消耗大量内存。确保Jetson Nano启用了足够的交换空间Swap。JetPack默认可能只设置了2GB可以扩展到4GB或6GB。# 检查当前swap sudo swapon --show # 如果不足可以创建swap文件注意对SD卡寿命有影响 sudo fallocate -l 4G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile # 永久生效需写入 /etc/fstabCPU/GPU频率锁定Jetson Nano有多个运行模式5W, 10W。在开发时可以将其设置为最大性能模式避免因散热导致的降频。sudo jetson_clocks5.4 传感器与硬件设备访问访问USB摄像头、激光雷达、IMU等设备是机器人开发的常态。USB设备使用-v /dev:/dev挂载通常可以访问大部分USB设备。但更精确的做法是使用--device参数挂载特定设备例如--device/dev/ttyUSB0。你需要知道设备在宿主机上的节点路径。摄像头对于V4L2摄像头除了挂载/dev还需要挂载/dev/video*设备文件和可能的/dev/v4l目录。有时还需要挂载/dev/media*。权限问题容器内用户如ros可能没有访问硬件设备的权限。解决方法有1) 在宿主机修改设备权限sudo chmod 666 /dev/ttyUSB0不推荐2) 在容器启动时使用--privileged有安全风险3) 最佳实践在Dockerfile中创建对应的用户组并在运行容器时通过--group-add参数将容器用户加入到宿主机的设备组如dialout组对应串口video组对应摄像头。6. 项目实践从零构建一个简单的机器人感知节点让我们通过一个具体的例子将所学串联起来。目标是在容器内创建一个ROS2节点使用Jetson Nano的CSI摄像头获取图像利用GPU加速的OpenCV进行边缘检测并发布处理后的图像话题。6.1 准备工作空间与包在宿主机上创建我们的工作空间目录并启动开发容器。# 在宿主机 mkdir -p ~/ros2_ws/src cd ~/ros2_ws # 使用之前提到的长命令启动容器并挂载工作空间 sudo docker run -it --rm --networkhost --gpus all -v /dev:/dev -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY$DISPLAY -v $HOME/ros2_ws:/home/ros/ros2_ws --name edge_detector your-username/ros2-humble-jetson-nano:latest /bin/bash进入容器后创建功能包cd /home/ros/ros2_ws/src ros2 pkg create --build-type ament_cmake edge_detector --dependencies rclcpp sensor_msgs cv_bridge image_transport OpenCV6.2 编写GPU加速的边缘检测节点编辑~/ros2_ws/src/edge_detector/src/edge_detector_node.cpp:#include rclcpp/rclcpp.hpp #include sensor_msgs/msg/image.hpp #include cv_bridge/cv_bridge.h #include opencv2/opencv.hpp #include opencv2/core/cuda.hpp // CUDA支持头文件 #include image_transport/image_transport.hpp class EdgeDetectorNode : public rclcpp::Node { public: EdgeDetectorNode() : Node(edge_detector) { // 声明参数是否使用GPU this-declare_parameterbool(use_gpu, true); use_gpu_ this-get_parameter(use_gpu).as_bool(); // 创建发布者和订阅者 it_ std::make_sharedimage_transport::ImageTransport(shared_from_this()); pub_ it_-advertise(image_edges, 1); sub_ it_-subscribe(image_raw, 1, std::bind(EdgeDetectorNode::imageCallback, this, std::placeholders::_1)); RCLCPP_INFO(this-get_logger(), Edge Detector started. GPU acceleration: %s, use_gpu_ ? ON : OFF); } private: void imageCallback(const sensor_msgs::msg::Image::ConstSharedPtr msg) { try { // 将ROS图像消息转换为OpenCV Mat (GPU版需要先转到CPU这里简化处理) cv_bridge::CvImagePtr cv_ptr cv_bridge::toCvCopy(msg, sensor_msgs::image_encodings::BGR8); cv::Mat src cv_ptr-image; cv::Mat edges; if (use_gpu_) { // 使用GPU路径 (示例使用CUDA加速的Canny边缘检测) // 注意实际OpenCV CUDA模块需要额外编译选项此处为逻辑示例 // cv::cuda::GpuMat gpu_src(src); // cv::cuda::GpuMat gpu_edges; // cv::Ptrcv::cuda::CannyEdgeDetector canny cv::cuda::createCannyEdgeDetector(50, 100); // canny-detect(gpu_src, gpu_edges); // gpu_edges.download(edges); RCLCPP_WARN(this-get_logger(), GPU path not fully implemented in example. Using CPU fallback.); cv::Canny(src, edges, 50, 100); // 临时用CPU版本 } else { // 使用CPU路径 cv::Canny(src, edges, 50, 100); } // 将处理后的图像转换回ROS消息并发布 cv_bridge::CvImage out_msg; out_msg.header msg-header; out_msg.encoding sensor_msgs::image_encodings::MONO8; out_msg.image edges; pub_.publish(out_msg.toImageMsg()); } catch (cv_bridge::Exception e) { RCLCPP_ERROR(this-get_logger(), cv_bridge exception: %s, e.what()); } } std::shared_ptrimage_transport::ImageTransport it_; image_transport::Publisher pub_; image_transport::Subscriber sub_; bool use_gpu_; }; int main(int argc, char **argv) { rclcpp::init(argc, argv); auto node std::make_sharedEdgeDetectorNode(); rclcpp::spin(node); rclcpp::shutdown(); return 0; }编辑package.xml和CMakeLists.txt确保依赖项正确。在CMakeLists.txt中需要找到OpenCV并链接opencv_cuda相关库如果使用完整CUDA加速。6.3 构建、运行与测试cd /home/ros/ros2_ws colcon build --packages-select edge_detector source install/setup.bash首先你需要一个发布image_raw话题的节点。如果你有CSI摄像头可以使用v4l2_camera节点需安装ros-humble-v4l2-camera包或jetson_csi_cam等专为Jetson优化的包。假设你已经有了图像源。然后运行我们的边缘检测节点# 使用GPU加速如果实现 ros2 run edge_detector edge_detector_node --ros-args -p use_gpu:true # 或使用CPU ros2 run edge_detector edge_detector_node --ros-args -p use_gpu:false使用rqt_image_view或RViz2订阅image_edges话题即可看到实时处理后的边缘图像。你可以通过对比CPU和GPU模式下的节点CPU占用率top命令和处理延迟直观感受硬件加速带来的优势。通过这个完整的小项目你实践了在预构建的Docker环境内创建包、编写节点、处理传感器数据、利用硬件加速并最终运行和调试的完整流程。这正是此镜像项目希望提供的“开箱即用”体验的核心让你免于环境搭建的困扰专注于机器人算法和应用逻辑本身。本文还有配套的精品资源点击获取
返回列表