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

资讯详情

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

云-端协同具身智能机器人:桥接层与实时调度系统构建指南

云-端协同具身智能机器人:桥接层与实时调度系统构建指南 在实际机器人开发项目中从实验室原型到能提供真实服务的产品中间横亘着巨大的工程鸿沟。高德地图在2024年世界机器人大会WRC上展示的“动量机器狗途途”其核心看点并非仅仅是机器狗本身而是它背后所代表的“具身智能”技术如何与高德的地图、导航、生活服务数据深度融合最终落地为“导盲”、“快递”、“巡检”、“陪伴”、“导览”等五种具体服务场景。这标志着机器人技术正从“能动”走向“有用”其关键在于将感知、决策、控制机器狗的“小脑”与云端的地图、语义、服务生态云端“大脑”进行高效协同。对于开发者而言理解这套架构远比单纯玩转一台机器狗更有价值。本文将深入拆解“云-端协同的具身智能机器人”的技术栈从概念、架构到关键模块的实现思路提供一个可供学习与实践的工程化视角。我们将重点关注如何构建连接机器狗本体与云端智能的“桥接层”并探讨在资源受限的嵌入式环境下如机器狗内置计算机如何设计实时调度系统。读完本文你将能理解一个服务型机器人系统的核心组成并掌握搭建其基础软件框架的关键技术要点。1. 理解“云-端协同”具身智能架构“具身智能”强调智能体通过与物理环境的实时交互来学习和完成任务。在“途途”这样的服务机器狗场景中完整的智能被拆解到了“端”机器狗本体和“云”两层这是一种兼顾实时响应与复杂智能的务实架构。1.1 云端“大脑”高精度语义地图与服务调度云端大脑的核心职责是提供机器狗自身传感器无法实时获取的全局性、先验性知识并处理复杂的认知和规划任务。高精度语义地图不同于普通的导航地图它融合了厘米级精度可能来自激光SLAM或视觉重建、道路网络、以及丰富的语义信息如“这是大楼A的东门”、“此处有三级台阶”、“这个区域是禁行区”。这些语义信息是机器狗理解任务指令如“去三楼送快递”的基础。全局路径与任务规划当收到“从A点送快递到B点”的指令后云端大脑会结合语义地图、实时交通信息对于室内可能是人流密度、电梯状态等规划出一条全局最优路径并将其分解为一系列可执行的子任务如“行进至电梯厅”、“呼叫电梯”、“进入电梯”、“在3楼出电梯”。生活服务集成这是高德的独特优势。云端大脑需要接入外卖、快递、导览信息等外部服务系统将用户的服务请求如“我要一杯咖啡”翻译成机器狗可执行的任务序列并处理订单状态同步、支付反馈等业务逻辑。1.2 端侧“小脑”实时感知、控制与局部决策端侧小脑部署在机器狗本体的计算单元如Jetson AGX Orin上负责处理毫秒级响应的任务保证机器狗的运动安全和基础行为能力。实时感知与定位融合激光雷达、摄像头、IMU、关节编码器等数据在云端提供的先验地图框架内进行实时定位Localization和周围动态障碍物检测。运动控制这是机器狗的核心。根据规划出的路径点或速度指令解算成每条腿的关节力矩控制信号。这涉及到复杂的动力学模型和平衡控制算法如MPC模型预测控制。局部重规划与避障当传感器发现前方出现未在地图中标注的临时障碍如一把突然出现的椅子时端侧小脑必须能在极短时间内通常100ms进行局部路径重规划绕开障碍而不必每次都请求云端。1.3 桥接层连接大脑与小脑的神经中枢桥接层是整套系统的工程核心它负责在云端大脑和端侧小脑之间建立可靠、高效、低延迟的通信与数据同步机制。它的设计直接决定了系统的响应速度和可靠性。一个典型的桥接层需要处理以下几类数据流下行指令流云端下发的任务序列、路径点、行为指令。上行状态流端侧上报的实时位姿、传感器数据、任务执行状态、异常告警。地图与模型更新流云端下发的地图增量更新、端侧视觉识别模型的OTA更新。控制权切换指令在自动模式和远程接管模式间切换。2. 构建机器狗系统的基础软件环境在开始编码之前需要搭建一个标准化的机器人开发环境。ROS 2Robot Operating System 2是目前机器人领域的事实标准中间件它提供了节点通信、设备驱动、工具链等一套完整的生态系统。2.1 基础环境与ROS 2安装我们以Ubuntu 22.04 LTS和ROS 2 Humble Hawksbill为例这是目前2024年一个长期支持且稳定的组合。假设开发机与机器狗本体均使用x86_64或ARM64架构的Linux系统。# 1. 设置语言环境 sudo apt update sudo apt install locales sudo locale-gen en_US en_US.UTF-8 sudo update-locale LC_ALLen_US.UTF-8 LANGen_US.UTF-8 export LANGen_US.UTF-8 # 2. 添加ROS 2软件源 sudo apt install software-properties-common sudo add-apt-repository universe sudo apt update sudo apt install curl -y 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 $(. /etc/os-release echo $UBUNTU_CODENAME) main | sudo tee /etc/apt/sources.list.d/ros2.list /dev/null # 3. 安装ROS 2基础包 sudo apt update sudo apt install ros-humble-desktop python3-argcomplete python3-colcon-common-extensions # 4. 配置环境变量 echo source /opt/ros/humble/setup.bash ~/.bashrc source ~/.bashrc2.2 创建机器人工作空间与功能包我们将创建一个代表机器狗端侧系统的工作空间。# 创建并进入工作空间 mkdir -p ~/tutu_ws/src cd ~/tutu_ws/src # 创建核心功能包。这里我们假设包名是 tutu_core ros2 pkg create --build-type ament_cmake --license Apache-2.0 tutu_core cd tutu_core # 创建必要的目录结构用于存放桥接层、控制节点等代码 mkdir -p include/tutu_core mkdir -p src/bridge src/control src/perception2.3 关键依赖配置编辑~/tutu_ws/src/tutu_core/package.xml添加项目依赖。以下是一些可能需要的依赖?xml version1.0? package format3 nametutu_core/name version0.1.0/version descriptionThe core package for Tutu robot dog/description maintainer emaildevexample.comYour Name/maintainer licenseApache-2.0/license buildtool_dependament_cmake/buildtool_depend !-- ROS 2 核心通信依赖 -- dependrclcpp/depend dependstd_msgs/depend dependgeometry_msgs/depend dependnav_msgs/depend dependsensor_msgs/depend dependtf2/depend dependtf2_ros/depend !-- 用于与云端通信例如使用 WebSocket 或 gRPC -- dependrclcpp_components/depend !-- 假设使用 FastDDS 作为底层DDS实现通常已包含 -- !-- 第三方库用于JSON解析、网络通信等 -- build_dependnlohmann_json/build_depend build_dependlibwebsockets-dev/build_depend !-- 或 grpc-dev -- export build_typeament_cmake/build_type /export /package同时编辑CMakeLists.txt确保能找到并链接这些依赖。3. 实现云端-端侧桥接层桥接层是系统的通信枢纽。我们将实现一个基于WebSocket的桥接层示例因为它易于调试且与Web服务生态兼容性好。在生产环境中可能会根据延迟和可靠性要求选择gRPC或专用的DDS网关。3.1 定义通信协议与消息格式首先需要定义云端与端侧交换的数据格式。我们使用JSON作为序列化格式。云端指令示例 (cloud_command.json):{ msg_id: cmd_123456, timestamp: 1697012345678, type: NAVIGATION_TASK, payload: { task_id: delivery_001, goal: { frame_id: map, pose: { x: 10.5, y: 5.2, theta: 1.57 } }, waypoints: [ {x: 1.0, y: 0.0}, {x: 5.0, y: 3.0} ], action_sequence: [MOVE_TO_GOAL, PLAY_SOUND:arrival, WAIT_FOR_CONFIRMATION] } }端侧状态上报示例 (robot_status.json):{ msg_id: status_789012, timestamp: 1697012345680, type: ROBOT_STATUS, payload: { battery: 85, pose: { x: 1.1, y: 0.1, theta: 0.05 }, velocity: { linear: 0.3, angular: 0.01 }, current_task_id: delivery_001, task_state: EXECUTING, obstacle_detected: false, error_code: 0 } }3.2 编写WebSocket桥接客户端端侧在~/tutu_ws/src/tutu_core/src/bridge/下创建websocket_bridge_client.cpp。// websocket_bridge_client.cpp #include memory #include string #include thread #include nlohmann/json.hpp #include websocketpp/client.hpp #include websocketpp/config/asio_client.hpp #include rclcpp/rclcpp.hpp #include std_msgs/msg/string.hpp #include geometry_msgs/msg/pose_stamped.hpp using json nlohmann::json; using WebSocketClient websocketpp::clientwebsocketpp::config::asio_tls_client; class WebSocketBridgeClient : public rclcpp::Node { public: WebSocketBridgeClient() : Node(websocket_bridge_client) { // 声明参数WebSocket服务器地址 this-declare_parameterstd::string(server_uri, wss://cloud-brain.example.com/robot/tutu_001); // 订阅来自本地其他节点如控制、感知节点的状态消息 status_sub_ this-create_subscriptiongeometry_msgs::msg::PoseStamped( /current_pose, 10, std::bind(WebSocketBridgeClient::poseCallback, this, std::placeholders::_1)); // 发布从云端接收到的指令 cloud_cmd_pub_ this-create_publisherstd_msgs::msg::String(/cloud_command, 10); // 初始化WebSocket客户端 client_.init_asio(); client_.set_tls_init_handler([](auto connection) { return std::make_sharedboost::asio::ssl::context(boost::asio::ssl::context::tlsv12_client); }); client_.set_message_handler([this](auto connection_hdl, auto message_ptr) { this-onWebSocketMessage(connection_hdl, message_ptr); }); client_.set_open_handler([this](auto connection_hdl) { RCLCPP_INFO(this-get_logger(), WebSocket连接已建立); this-connection_handle_ connection_hdl; // 连接成功后发送注册或心跳消息 this-sendRobotMetadata(); }); // 启动连接线程 std::thread([this]() { this-connect(); }).detach(); // 启动定时心跳线程 heartbeat_timer_ this-create_wall_timer( std::chrono::seconds(5), [this]() { this-sendHeartbeat(); }); } private: void connect() { std::string uri this-get_parameter(server_uri).as_string(); websocketpp::lib::error_code ec; auto connection client_.get_connection(uri, ec); if (ec) { RCLCPP_ERROR(this-get_logger(), 连接创建失败: %s, ec.message().c_str()); return; } client_.connect(connection); client_.run(); // 这个调用会阻塞因此运行在独立线程中 } void onWebSocketMessage(websocketpp::connection_hdl hdl, WebSocketClient::message_ptr msg) { try { json j json::parse(msg-get_payload()); std::string msg_type j[type]; if (msg_type NAVIGATION_TASK || msg_type ACTION_COMMAND) { // 将云端指令转换为ROS 2消息并发布到本地话题 std_msgs::msg::String cmd_msg; cmd_msg.data msg-get_payload(); cloud_cmd_pub_-publish(cmd_msg); RCLCPP_INFO(this-get_logger(), 收到云端指令: %s, msg_type.c_str()); } else if (msg_type MAP_UPDATE) { // 处理地图更新 RCLCPP_INFO(this-get_logger(), 收到地图更新); } } catch (const std::exception e) { RCLCPP_ERROR(this-get_logger(), 解析WebSocket消息失败: %s, e.what()); } } void poseCallback(const geometry_msgs::msg::PoseStamped::SharedPtr msg) { // 构造状态上报JSON json status_msg; status_msg[type] ROBOT_STATUS; status_msg[timestamp] this-now().nanoseconds() / 1e9; // 转换为秒 status_msg[payload][pose][x] msg-pose.position.x; status_msg[payload][pose][y] msg-pose.position.y; // ... 填充其他状态字段 // 发送状态到云端 if (connection_handle_.lock()) { client_.send(connection_handle_, status_msg.dump(), websocketpp::frame::opcode::text); } } void sendRobotMetadata() { json meta; meta[type] ROBOT_REGISTER; meta[robot_id] tutu_001; meta[capabilities] {NAVIGATION, OBJECT_DETECTION, VOICE_PLAYBACK}; client_.send(connection_handle_, meta.dump(), websocketpp::frame::opcode::text); } void sendHeartbeat() { json hb; hb[type] HEARTBEAT; hb[timestamp] this-now().nanoseconds() / 1e9; if (connection_handle_.lock()) { client_.send(connection_handle_, hb.dump(), websocketpp::opcode::text); } } WebSocketClient client_; websocketpp::connection_hdl connection_handle_; rclcpp::Subscriptiongeometry_msgs::msg::PoseStamped::SharedPtr status_sub_; rclcpp::Publisherstd_msgs::msg::String::SharedPtr cloud_cmd_pub_; rclcpp::TimerBase::SharedPtr heartbeat_timer_; }; int main(int argc, char* argv[]) { rclcpp::init(argc, argv); auto node std::make_sharedWebSocketBridgeClient(); rclcpp::spin(node); rclcpp::shutdown(); return 0; }3.3 编译与运行桥接客户端更新CMakeLists.txt以编译此节点并链接必要的库如websocketpp,ssl,crypto。然后进行编译和测试。# 在工作空间根目录下 cd ~/tutu_ws colcon build --packages-select tutu_core source install/setup.bash # 在一个终端运行桥接客户端需要先启动ROS 2 ros2 run tutu_core websocket_bridge_client注意此示例省略了完整的错误处理、重连逻辑和TLS证书验证生产环境必须补全。同时WebSocket服务器端需要相应实现用于接收状态、下发指令。4. 设计端侧实时调度与优先级系统机器狗的端侧计算资源有限CPU、内存但任务繁多感知、定位、控制、通信、用户交互。必须设计一个实时调度系统确保高优先级任务如平衡控制总能及时获得CPU时间避免因低优先级任务如日志上传阻塞导致机器狗失稳。4.1 Linux实时调度策略与优先级设置Linux提供了SCHED_FIFO和SCHED_RR等实时调度策略。我们可以通过设置线程的调度策略和优先级来管理任务。创建一个调度管理器头文件include/tutu_core/scheduler.hpp// scheduler.hpp #ifndef TUTU_CORE_SCHEDULER_HPP #define TUTU_CORE_SCHEDULER_HPP #include pthread.h #include string #include unordered_map namespace tutu_core { // 定义任务优先级枚举 enum class TaskPriority : int { CRITICAL 90, // 最高运动控制、安全监控 HIGH 70, // 高定位、避障 MEDIUM 50, // 中任务规划、状态机 LOW 30, // 低数据记录、状态上报 BACKGROUND 10 // 后台日志上传、诊断 }; class RealtimeScheduler { public: RealtimeScheduler(); ~RealtimeScheduler(); // 设置当前线程的调度策略和优先级 static bool setThreadPriority(pthread_t thread_id, int policy, int priority); // 便捷方法设置ROS 2节点的回调组或特定线程的优先级 static bool setThisThreadPriority(TaskPriority prio); // 获取当前线程的调度参数 static void getCurrentThreadScheduling(int* policy, int* priority); private: static const std::unordered_mapTaskPriority, int priority_map_; }; } // namespace tutu_core #endif实现文件src/bridge/scheduler.cpp// scheduler.cpp #include tutu_core/scheduler.hpp #include sched.h #include sys/resource.h #include iostream namespace tutu_core { const std::unordered_mapTaskPriority, int RealtimeScheduler::priority_map_ { {TaskPriority::CRITICAL, 90}, {TaskPriority::HIGH, 70}, {TaskPriority::MEDIUM, 50}, {TaskPriority::LOW, 30}, {TaskPriority::BACKGROUND, 10} }; bool RealtimeScheduler::setThreadPriority(pthread_t thread_id, int policy, int priority) { sched_param param; param.sched_priority priority; int ret pthread_setschedparam(thread_id, policy, param); if (ret ! 0) { // 需要root权限或CAP_SYS_NICE能力 std::cerr Failed to set thread scheduling (errno: ret ). Need CAP_SYS_NICE capability or run as root. std::endl; return false; } return true; } bool RealtimeScheduler::setThisThreadPriority(TaskPriority prio) { auto it priority_map_.find(prio); if (it priority_map_.end()) { return false; } int priority_value it-second; // 对于关键控制任务使用SCHED_FIFO先进先出直到主动让出CPU // 对于其他高优先级任务可以使用SCHED_RR时间片轮转 int policy (prio TaskPriority::CRITICAL) ? SCHED_FIFO : SCHED_RR; pthread_t this_thread pthread_self(); return setThreadPriority(this_thread, policy, priority_value); } void RealtimeScheduler::getCurrentThreadScheduling(int* policy, int* priority) { sched_param param; pthread_getschedparam(pthread_self(), policy, param); *priority param.sched_priority; } } // namespace tutu_core4.2 在ROS 2节点中应用实时调度ROS 2节点的回调默认在通用的线程池中执行。为了对关键任务进行实时调度我们可以使用回调组Callback Group特别是MutuallyExclusiveCallbackGroup或ReentrantCallbackGroup并结合我们自己的线程池或设置线程属性。以下是一个高优先级控制节点的示例它在启动时提升自身主线程的优先级并为其关键定时器回调创建一个独占的高优先级线程。// high_priority_control_node.cpp #include tutu_core/scheduler.hpp #include rclcpp/rclcpp.hpp #include chrono class HighPriorityControlNode : public rclcpp::Node { public: HighPriorityControlNode() : Node(high_priority_control) { // 1. 在节点构造初期提升当前线程主线程优先级 if (!tutu_core::RealtimeScheduler::setThisThreadPriority(tutu_core::TaskPriority::CRITICAL)) { RCLCPP_WARN(this-get_logger(), Failed to set critical priority. Control loop may be delayed.); } // 2. 创建一个独占的回调组后续可以将高优先级回调添加进去 // 虽然回调组本身不设置优先级但它允许我们将回调分配到特定的执行器线程 high_prio_cb_group_ this-create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive); // 3. 创建一个高频率的定时器用于运动控制循环例如500Hz // 将其与高优先级回调组关联 control_timer_ this-create_wall_timer( std::chrono::milliseconds(2), // 500Hz std::bind(HighPriorityControlNode::controlLoopCallback, this), high_prio_cb_group_); // 关联回调组 RCLCPP_INFO(this-get_logger(), High priority control node initialized.); } private: void controlLoopCallback() { // 这里是核心控制算法例如 // - 读取当前关节编码器、IMU数据 // - 计算期望的关节力矩 // - 下发指令到电机驱动器 // 此函数必须高效执行避免阻塞操作如文件IO、网络请求。 // 实际控制量计算... // publishMotorCommand(...); } rclcpp::CallbackGroup::SharedPtr high_prio_cb_group_; rclcpp::TimerBase::SharedPtr control_timer_; }; int main(int argc, char* argv[]) { rclcpp::init(argc, argv); // 为了更精细的控制可以创建多线程执行器并为不同回调组分配不同优先级的线程 // 但这里为了简化我们依赖操作系统对节点主线程的优先级设置 auto node std::make_sharedHighPriorityControlNode(); // 使用单线程执行器 rclcpp::executors::SingleThreadedExecutor executor; executor.add_node(node); executor.spin(); rclcpp::shutdown(); return 0; }4.3 系统配置与能力Capabilities授予要让实时调度生效运行程序的用户需要CAP_SYS_NICE能力或者直接以root身份运行不推荐。更安全的方式是通过setcap命令赋予二进制文件能力。# 编译节点后找到生成的可执行文件 cd ~/tutu_ws colcon build --packages-select tutu_core # 赋予实时调度能力 sudo setcap cap_sys_niceeip ./install/tutu_core/lib/tutu_core/high_priority_control_node # 验证能力 getcap ./install/tutu_core/lib/tutu_core/high_priority_control_node # 应输出... cap_sys_niceeip5. 系统集成、验证与常见问题排查将桥接层、控制节点、感知节点等集成起来并验证数据流是否通畅。5.1 启动与验证流程启动ROS 2核心ros2 daemon start(通常ros2 run会自动启动)。启动桥接客户端ros2 run tutu_core websocket_bridge_client。观察日志确认连接到模拟或真实的云端服务器。启动高优先级控制节点ros2 run tutu_core high_priority_control_node。使用htop或chrt命令查看其线程优先级是否已提升。# 查找进程PID ps aux | grep high_priority_control_node # 查看线程调度信息 sudo chrt -p PID_of_control_node_thread发送测试指令可以通过ROS 2命令行工具模拟云端下发指令。# 发布一个模拟的云端指令到 /cloud_command 话题 ros2 topic pub /cloud_command std_msgs/msg/String {data: {\type\:\NAVIGATION_TASK\,\payload\:{\goal\:{\x\:1,\y\:0}}}} --once监控状态上报在运行桥接客户端的终端观察是否有包含位姿信息的JSON消息被打印或发送出去。5.2 常见问题与排查路径问题现象可能原因检查方式处理建议桥接客户端无法连接云端1. 网络不通或防火墙阻止。2. 服务器URI错误或证书问题。3. 库依赖未正确链接。1.ping/telnet测试服务器端口。2. 检查server_uri参数确认是ws://还是wss://。3. 查看编译日志和ldd命令检查动态库。1. 配置网络或防火墙规则。2. 修正URI对于wss确保CA证书可用。3. 检查CMakeLists.txt链接选项重新编译。控制节点优先级设置失败1. 未授予CAP_SYS_NICE能力。2. 优先级数值超出范围1-99。3. 在容器或虚拟化环境中受限。1. 运行getcap检查二进制文件能力。2. 检查priority_map_中的数值。3. 检查cgroup或容器配置。1. 使用sudo setcap授予能力。2. 确保优先级在有效范围内SCHED_FIFO/SCHED_RR要求优先级0。3. 确保宿主机和容器配置允许实时调度。云端指令接收但未执行1. 话题名称不匹配。2. 消息格式解析错误。3. 执行该指令的节点未启动。1. 使用ros2 topic list和ros2 topic echo查看消息是否到达正确话题。2. 在桥接客户端的onWebSocketMessage中添加调试日志。3. 检查节点运行状态ros2 node list。1. 统一话题命名使用参数或全局定义。2. 增加JSON解析的异常捕获和日志输出。3. 使用launch文件确保所有依赖节点按顺序启动。系统运行后实时性不达标1. 低优先级任务如日志占满CPU。2. 内存不足导致交换SWAP。3. 其他进程如桌面GUI干扰。1. 使用top -H查看各线程CPU占用和优先级。2. 使用free -h查看内存和Swap使用。3. 检查系统负载uptime。1. 使用cgroups或nice限制低优先级任务的CPU份额。2. 增加物理内存或优化代码减少内存使用禁用Swap (sudo swapoff -a)。3. 在专用的机器人操作系统如Ubuntu Server上运行关闭非必要服务。WebSocket连接频繁断开1. 网络不稳定。2. 心跳机制缺失或间隔太长。3. 服务器端主动断开空闲连接。1. 检查网络丢包率。2. 确认心跳线程正常运行并检查发送日志。3. 查看服务器端断开连接时的返回码。1. 实现自动重连机制并加入指数退避策略。2. 调整心跳间隔如3-10秒确保小于服务器的空闲超时时间。3. 在连接断开回调中触发重连逻辑。5.3 生产环境最佳实践通信冗余与降级不要只依赖一条通信链路。当云端连接断开时端侧应能基于最后已知的指令和本地地图执行降级策略如原地等待、沿原路返回充电桩。全面的健康检查除了心跳还应监控关键线程的存活状态、CPU/内存使用率、传感器数据频率、控制环路延迟等并主动上报异常。配置外置化所有服务器地址、端口、超时时间、优先级参数都应通过配置文件或参数服务器管理避免硬编码。详尽的日志记录使用结构化日志如JSON格式记录关键事件、收到的指令、发送的状态、异常堆栈。日志应分级DEBUG, INFO, WARN, ERROR并支持远程拉取。安全的权限管理为机器人进程创建专用用户和组仅授予必要的能力如CAP_SYS_NICE,CAP_NET_BIND_SERVICE遵循最小权限原则。OTA更新机制设计安全的固件和软件更新流程支持回滚。桥接层本身应作为更新通道的一部分。从“导盲路”到“五种生活服务”的跨越本质上是机器人“端侧智能”与“云端智能”协同水平的一次质变。实现这一目标稳定高效的桥接层和可靠的端侧实时调度系统是看不见的基石。本文提供的代码和思路是一个起点在实际项目中你需要根据具体的硬件平台如不同的机器狗SDK、通信协议和业务逻辑进行大量适配和优化。下一步可以深入探索基于ROS 2的LifecycleNode管理节点状态、使用ros2_control框架统一机器人控制接口以及如何将高德提供的语义地图数据如PBF格式转换为机器人可用的代价地图Costmap从而最终完成从云端任务到端侧动作的完整闭环。
返回列表