ROS达妙机械臂main函数 📅 发布时间:2026/7/15 15:37:39 👁️ 浏览次数: ros::init(argc, argv, damiao_hardware_node); ros::NodeHandle nh; ros::NodeHandle nh_private(~);ros::init你的程序来到 ROS 世界第一件事就是去注册中心登记名字“大家好我是damiao_hardware_node”。nh与nh_private(~)你向系统申请了两部通讯工具。nh公共大喇叭用来向全网广播你的关节状态/joint_states。nh_private私密对讲机带波浪号~专门用来悄悄读取 launch 文件里加载的属于你自己的motor_config.yaml配置文件绝不会和其他节点弄混。damiao::DmHW robot; if (!robot.init(nh, nh_private)) { ROS_ERROR(Failed to initialize Damiao Hardware Interface!); return -1; }init串口初始化使能电机开启读取电机数据线程注册关节位置接口ros上层得知要控制电机只需要王cmd_pos的地址写数据就行controller_manager::ControllerManager cm(robot, nh);为什么必须要传robot解决内存共享问题robot是什么它是你自己写的DmHW类的实例。在这个实例的内存里存着你之前注册的各种接口jointStateInterface_、positionJointInterface_以及电机实际位置 (pos) 和目标位置 (cmd_pos) 的物理内存地址。传递robot的底层逻辑ControllerManager(cm) 本身只是一个纯数学算法库它生来就是没有数据的。当你使用取地址符把robot传给它时cm就直接获得了访问robot内部变量的权限。使用结果从此以后cm内部的控制算法在计算时不需要调用任何函数去向robot索要数据而是直接去读写robot内存里的pos和cmd_pos变量。这在 C 中叫做“零拷贝数据交互”效率极高。2. 为什么必须要传nh解决 ROS 通信问题nh是什么ros::NodeHandle是 ROS 系统提供的通信接口。有了它C 程序才能在 ROS 网络中发布话题Topic或创建服务Service。传递nh的底层逻辑cm需要接收外部的指令比如你想启动哪个控制器、停止哪个控制器。通过接收你传进来的nhcm会在后台自动为你生成并注册一系列标准的 ROS 服务Services。使用结果只要这行代码一执行你在终端里输入rosservice list就会立刻看到多出了一大堆服务比如/controller_manager/load_controller/controller_manager/switch_controller/controller_manager/list_controllers此时外部程序就可以通过调用这些服务来操控你的 C 代码。这行代码仅仅是完成了“初始化”。在真正的机器人运行中它是按以下 3 个步骤被使用的第一步代码层面的初始化就是这行代码本身当 C 的main函数执行到这一行时cm对象被创建。它绑定了底层硬件内存robot并在 ROS 网络中注册了控制服务利用nh。此时算法处于待机状态没有任何运算发生。第二步外部唤醒Launch 文件中的spawner节点在你的.launch文件中有一行专门针对它的指令node namecontroller_spawner pkgcontroller_manager typespawner argsjoint_state_controller arm_controller/这个叫spawner的脚本会去调用第一步里cm创建的 ROS 服务。它对cm下达指令“请立刻加载joint_state_controller和arm_controller这两个控制算法并让它们开始运行。”此时cm会根据指令在内存中把这两个算法实例化。第三步循环调用运算C 代码中的cm.update在 C 的while(ros::ok())死循环中你写了cm.update(current_time, elapsed_time);。每次执行到这句话cm就会触发刚才加载的那两个控制算法。算法会利用第一步拿到的robot权限读取电机的实际角度。算法如arm_controller接收 MoveIt 传来的目标轨迹利用 PID 公式计算出当前的控制量并直接把计算结果覆盖写回到robot的cmd_pos内存地址中。随后你的robot.write()函数就会把这个新的cmd_pos变成 CAN 数据发给达妙电机。ros::AsyncSpinner spinner(1); spinner.start();ros::AsyncSpinner这是 ROS 提供的一个异步多线程处理器Spinner 意为“轮询器”。(1)括号里的1代表你想分配几个独立的子线程。写1就意味着你在主线程跑while循环的那个之外额外开辟了 1 个平行的后台线程专门用来处理 ROS 的消息回调。在后面有while循环需要有独立的子线程去处理movelt发过来的数据spinner.start();函数作用启动这个后台线程。ros::Rate rate(200); ros::Time last_time ros::Time::now();代表频率是 200Hz。意思是告诉程序“接下来你要干的活必须每秒钟执行 200 次记录下程序运行到这一行的当前绝对时间。ROS_INFO(Damiao Hardware Node Started!);打印出一句话“达妙硬件节点已启动”while (ros::ok()) {死循环ros::Time current_time ros::Time::now(); ros::Duration elapsed_time current_time - last_time; last_time current_time;看一眼现在几点了存到current_time当前时间里。用现在的时刻减去刚才记录的时刻算出了一个时间段elapsed_time流逝的时间差。控制管家cm里的 PID 算法比如算速度、算加速度极度依赖物理时间。如果时间算不准算出来的控制指令就是错的机械臂就会疯狂发抖。robot.read(current_time, elapsed_time); // 读电机调用你写的底层硬件代码通过串口去问达妙电机“你现在实际上转到多少度了” 然后把度数存进共享内存里。cm.update(current_time, elapsed_time); // 算控制控制管家ControllerManager出场它把刚才读上来的真实角度和 MoveIt 下发的目标角度做对比。结合时间差elapsed_time它经过一顿复杂的数学运算算出“为了消除误差下一刻电机应该转到某某位置。” 并把这个新位置写进内存。robot.write(current_time, elapsed_time); // 写电机再次调用底层代码把刚才管家算出来的新目标位置打包成 CAN 通信的十六进制指令顺着数据线狠狠地发给物理电机。电机收到后就会嗡嗡地转动一丝丝距离。
靠谱的海关数据生产厂家 开篇:定下基调随着国际贸易的不断发展,海关数据成为了企业决策的重要依据。为了帮助大家更好地选择合适的海关数据提供商,我们对市场上主流的产品进行了深度测评。本次测评将基于真实数据与体验,无商业倾向。参与产品:… 2026/7/13 2:06:37
基于深度学习的条形码识别检测系统|全新web界面|多模态|AI大模型智能分析|YOLOv8、YOLOv10、YOLOv11、YOLOv12 摘要 本文设计并实现了一个基于深度学习的高效条形码检测与分析系统。系统采用前后端分离架构,后端基于SpringBoot框架,前端提供现代化的Web交互界面,并利用MySQL数据库进行数据持久化管理。在核心检测算法上,系统创新性地集成并对… 2026/7/15 10:40:52
基于深度学习的安全锥识别检测系统|全新web界面|多模态|AI大模型智能分析|YOLOv8、YOLOv10、YOLOv11、YOLOv12 摘要 随着道路交通施工、临时交通管制等场景的日益频繁,安全锥作为重要的道路安全警示设施,其部署的规范性、完整性直接关系到现场作业人员与过往车辆的安全。传统的人工巡检方式存在效率低下、成本高昂、难以实现全天候监控等弊端。为此,本… 2026/7/14 15:18:40
游戏AI实战:用行为树打造智能僵尸敌人系统 1. 项目概述:当僵尸“活”起来,游戏才真正开始 在生存类游戏里,僵尸从来不只是会移动的靶子。一个只会直线冲向你、攻击模式单一的僵尸,玩上十分钟就会让人感到乏味。真正的挑战和沉浸感,来自于那些会观察、会思考、会… 2026/7/15 15:37:36
CANN Ascend C Mutex核内流水线同步样例 Mutex核内流水线同步样例 概述 本样例演示Mutex::Lock、Mutex::Unlock、AllocMutexID和ReleaseMutexID核内流水线同步接口的使用方法。样例首先通过AllocMutexID从框架获取MutexID,然后使用Mutex::Lock和Mutex::Unlock锁定指定流水再释放流水来实现PIPE_MTE2、PIP… 2026/7/15 15:33:31
常用 IP 协议号大全(IP 层承载的上层协议) 一、常用基础协议号 ICMP:1TCP:6UDP:17GRE:47ESP:50AH:51 二、网络安全 / VPN 类常用 IPIP(IPv4 over IPv4 隧道):4EIGRP(思科路由协议)&#… 2026/7/15 15:33:31
终极VR视频转换指南:如何用VR-Reversal解锁360度自由视角观看体验 终极VR视频转换指南:如何用VR-Reversal解锁360度自由视角观看体验 【免费下载链接】VR-reversal VR-Reversal - Player for conversion of 3D video to 2D with optional saving of head tracking data and rendering out of 2D copies. 项目地址: https://gitcod… 2026/7/15 15:31:29
小程序毕设项目: 基于 小程序的碎片化学习平台 基于 SpringBoot + 微信小程序的课程学习答疑系统的设计与实现(源码+文档,讲解、调试运行,定制等) 博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am… 2026/7/15 15:31:29
如何用HowToCookOnMiniprogram快速找到适合的菜谱:AI智能食材匹配教程 如何用HowToCookOnMiniprogram快速找到适合的菜谱:AI智能食材匹配教程 【免费下载链接】HowToCookOnMiniprogram 程序员做菜指南 for Miniprogram,将程序员精神贯彻到底 项目地址: https://gitcode.com/gh_mirrors/ho/HowToCookOnMiniprogram 还在… 2026/7/15 15:29:26
行星减速机的工作原理是什么?从齿轮运动关系到减速比计算 一、行星齿轮机构的组成 标准行星齿轮机构主要包括: 太阳轮; 行星轮; 内齿圈; 行星架。 太阳轮位于机构中心。 多个行星轮围绕太阳轮均匀布置,行星轮内侧与太阳轮外啮合,外侧与内齿圈内啮合。 行星轮通过轴… 2026/7/15 0:03:00
阅读Java开源框架源码的心得分享! 前几日闲来无事有幸看到了一位博主分享自己阅读开源框架源码的心得,看了之后也引发了我的一些深度思考。我们为什么要看源码?我们该怎么样去看源码? 其中前者那位博主描述的我觉得很全了(如下图所示),就不做… 2026/7/15 0:03:00
【LINUX】驱动 【LINUX驱动】【字符设备】【中断】【Platform】【网课 设备树】【GPIO】【PINCTRL】【INPUT】【IIC】【SPI】【网络驱动】【屏幕驱动】【一 设备树】【二 内核模块编译】【三 基本驱动框架】【四 Platform总线设备驱动框架】【五 驱动子系统】【六 综合】 2026/7/15 0:07:01
Git reset 与 revert 深度对比:5个关键差异与 3 种典型应用场景 Git Reset 与 Revert 深度对比:5个关键差异与3种典型应用场景在团队协作开发中,代码版本管理如同行走钢丝——一步失误可能导致整个项目陷入混乱。作为Git进阶用户,你是否曾在深夜面对错误的提交束手无策?是否在强制推送后收到同事… 2026/7/13 8:31:55
GitHub 学生包申请避坑:5个常见失败原因与开发者工具调试方案 GitHub 学生包申请技术排障指南:5个高频失败场景与开发者工具实战方案第一次尝试申请GitHub学生包时,我盯着屏幕上那个不断转圈的加载动画整整15分钟,最终只等来了一行冰冷的错误提示。这可能是许多开发者共同的经历——明明按照教程操作&… 2026/7/14 18:25:04
冒烟测试用例设计规范:5%-10%覆盖率下的3类核心场景与执行标准 冒烟测试用例设计的黄金法则:5%-10%覆盖率下的精准筛选策略在快节奏的敏捷开发环境中,冒烟测试作为质量保障的第一道防线,其重要性不言而喻。当测试资源有限而时间紧迫时,如何从海量测试用例中精准筛选出那关键的5%-10%࿰… 2026/7/14 5:09:41