ROS中的diagnostics模块

本文围绕ROS的diagnostics模块展开,该模块用于收集系统状态和硬件信息以分析、排障和记录。介绍了diagnostics的消息、消息发布工具diagnostic_updater,还阐述了数据的分析整合、查看工具及转换工具等内容,帮助用户更好地使用该模块。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

(关于该模块的参考资料较少,下面整理的仅是个人的理解,有不恰当的地方欢迎指正,更具体的内容参考ROS官网说明)
diagnostics意为诊断,该模块旨在从系统中收集各种状态信息和硬件信息,以进行分析,故障排除和记录。 工具链中包含用于收集,发布,分析和查看diagnostics数据的工具。主要内容有:

(1) diagnostics的消息

诊断工具链围绕/diagnostics主题构建。 在此主题上,系统通过diagnostic_msgs/DiagnosticArray类型的消息(定义如下)发布设备的各种状态,每个状态都关联相应的诊断任务。

Header header #for timestamp
DiagnosticStatus[] status # an array of components being reported on

其中DiagnosticStatus具体信息包括:

byte level               # level of operation enumerated above 
string name              # a description of the test/component reporting
string message           # a description of the status
string hardware_id       # 硬件ID
KeyValue[] values        # an array of values associated with the status

level 的值设定:

byte OK=0
byte WARN=1
byte ERROR=2
byte STALE=3

(2)消息发布 diagnostic_updater

diagnostic_updater是diagnostics模块的核心,用于:

  • 在设备驱动程序上发布传感器数据主题的状态
  • 报告硬件设备已关闭
  • 当值超出范围时报告错误,例如温度

API:

  • diagnostic_updater::DiagnosticStatusWrapper

diagnostic_updater::DiagnosticStatusWrapper 类用于处理与diagnostic_msgs/DiagnosticStatus消息相关的操作如设置DiagnosticStatus中各个字段的信息,具体可以参考文章后面的例子,其成员函数有:

void 	add (const std::string &key, const T &val)
 	# Add a key-value pair. 
void 	add (const std::string &key, const bool &b)
 	# For bool, diagnostic value is "True" or "False". 
void 	addf (const std::string &key, const char *format,...)
 	# Add a key-value pair using a format string. 
void   clear ()
 	# Clear the key-value pairs. 
........
  • diagnostic_updater::Updater

diagnostic_updater::Updater 类本质上是一个诊断任务的向量,通过该类可以添加或删除diagnostic任务、以及确定任务更新频率等,其用法可以参看文章最后的例子。该类中的每一个任务均通过DiagnosticStatusWrapper维护一个DiagnosticStatus状态。

  • diagnostic_updater::DiagnosedPublisher

对于一个标准的ros:Publisher,这个类允许将ros:Publisher和topicDiagnosis组合在一起。如下:

   ros::Publisher pub_;
   pub_ = nh_.advertise<sensor_msgs::PointCloud2>("cloud", 100);

   void produce_diagnostics(diagnostic_updater::DiagnosticStatusWrapper &stat);{
                     .........
}

  diagnostic_updater::DiagnosedPublisher<sensor_msgs::PointCloud2>* diagnosticPub_;

  diagnosticPub_ = new diagnostic_updater::DiagnosedPublisher<sensor_msgs::PointCloud2>(pub_, *diagnostics_,
      diagnostic_updater::FrequencyStatusParam(&expected_frequency_, &expected_frequency_, 0.1, 10),
      diagnostic_updater::TimeStampStatusParam(-1, 1.3 * 1.0 / 12.5));

  diagnostics_->setHardwareID("none");  
  diagnostics_->add("device info", this, &produce_diagnostics);

发布时调用

   sensor_msgs::PointCloud2 msg;
   diagnosticPub_->publish(msg);

(3)diagnostics数据的分析与整合

diagnostic_aggregator包含一个ros节点aggregator_node,主要用于在运行时对诊断消息进行分类和分析。该节点的订阅发布消息如下:

  • Subscribed Topics
    /diagnostics (diagnostic_msgs/DiagnosticArray)

  • Published Topics
    /diagnostics_agg(diagnostic_msgs/DiagnosticArray)
    /diagnostics_toplevel_state (diagnostic_msgs/DiagnosticStatus)

如果机器人有电机驱动器、SICK激光扫描仪、Videre摄像机和几个电池的诊断信息,诊断输入可能有状态名称:

Left Wheel
Right Wheel
SICK Frequency
SICK Temperature
SICK Connection Status
Stereo Left Camera
Stereo Right Camera
Stereo Analysis
Stereo Connection Status
Battery 1 Level
Battery 2 Level
Battery 3 Level
Battery 4 Level
Voltage Status

使用diagnostic aggregator, 我们可以将这些诊断消息以一种易于理解的形式组织起来,以便在robot_monitor中显示。即将类别的名称放在状态名称的前面,然后用"/"分割。

My Robot/Wheels/Left
My Robot/Wheels/Right
My Robot/SICK/Frequency
My Robot/SICK/Temperature
My Robot/SICK/Connection Status
My Robot/Stereo/Left Camera
My Robot/Stereo/Right Camera
My Robot/Stereo/Analysis
My Robot/Stereo/Connection Status
My Robot/Power System/Battery 1 Level
My Robot/Power System/Battery 2 Level
My Robot/Power System/Battery 3 Level
My Robot/Power System/Battery 4 Level
My Robot/Power System/Voltage Status

使用上述输入,机器人监视器将数据分类如下:

My Robot
  -- Wheels
    -- Left
    -- Right
  -- SICK
    -- etc ...
  -- Stereo
  -- Power System

(4)diagnostics数据的查看工具

rqt_robot_monitor 用于直观的查看 diagnostic_aggregator发布的消息,作用类似于rqt_bag.

(5)diagnostics数据的转换工具

diagnostic_analysis工具可以将diagnostics产生的数据bag文件转换为CSV文件,以便用现成的电子表格软件绘制或查看。

参考:
http://wiki.ros.org/diagnostics
http://wiki.ros.org/diagnostic_aggregator#Example
http://wiki.ros.org/diagnostic_updater?distro=melodic

 #include <diagnostic_updater/diagnostic_updater.h>
 #include <std_msgs/Bool.h>
 #include <diagnostic_updater/publisher.h>

 // 解决与windows.h中宏 ERROR定义的冲突
 #ifdef ERROR
 #undef ERROR
 #endif

 double time_to_launch;
 ////////////////////////////////////////////任务函数////////////////////////////////////////////////////
 void dummy_diagnostic(diagnostic_updater::DiagnosticStatusWrapper &stat)
  {
        // summary 和summaryf 函数用于设置 level 与message,不同点在于后者可以添加变量的输出如%f 。
         if (time_to_launch < 10)
          stat.summaryf(diagnostic_msgs::DiagnosticStatus::ERROR, "Buckle your seat belt. Launch in %f seconds!", time_to_launch);
         else
           stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "Launch is in a long time. Have a soda.");
         // add and addf 函数用于增加 与该状态有关的key-value 对, 另外,add可以自动实现字符串的格式转换。 addf 支持格式化输出如%f
        stat.add("Diagnostic Name", "dummy");
        stat.add("Time to Launch", time_to_launch);
        stat.addf("Geeky thing to say", "The square of the time to launch %f is %f",   time_to_launch, time_to_launch * time_to_launch);
       }
 /////////////////////////////////////////用类的方法添加任务////////////////////////////////////////////////////  
class DummyClass
      { 
      public:  void  produce_diagnostics(diagnostic_updater::DiagnosticStatusWrapper &stat)
          {
              stat.summary(diagnostic_msgs::DiagnosticStatus::WARN, "This is a silly updater.");
              stat.add("Stupidicity of this updater", 1000.);
           } 
       };

      class DummyTask : public diagnostic_updater::DiagnosticTask
       {
       public:
        DummyTask() : DiagnosticTask("Updater Derived from DiagnosticTask")
        {}
         void run(diagnostic_updater::DiagnosticStatusWrapper &stat)
          {
            stat.summary(diagnostic_msgs::DiagnosticStatus::WARN, "This is another silly updater.");
            stat.add("Stupidicity of this updater", 2000.);
         }
        };
   ////////////////////////////////////////////任务函数的组合示例////////////////////////////////////////////////////    
      void check_lower_bound(diagnostic_updater::DiagnosticStatusWrapper &stat)
       {
         if (time_to_launch > 5)
          stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "Lower-bound OK");
        else
         stat.summary(diagnostic_msgs::DiagnosticStatus::ERROR, "Too low");
          stat.add("Low-Side Margin", time_to_launch - 5);
       }
     
   void check_upper_bound(diagnostic_updater::DiagnosticStatusWrapper &stat)
     {
       if (time_to_launch < 10)
        stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "Upper-bound OK");
        else
         stat.summary(diagnostic_msgs::DiagnosticStatus::WARN, "Too high");
         stat.add("Top-Side Margin", 10 - time_to_launch);
     }
   
     int main(int argc, char **argv)
     {
        ros::init(argc, argv, "diagnostic_updater_example");
        ros::NodeHandle nh;
   
      //Updater类发布 /diagnostics消息, 并且有一个~diagnostic_period 参数设置发布频率
      
      diagnostic_updater::Updater updater;
      
       //关联ID,以下两种方法均可设置ID ,不设置时建议填入none,否则会警告
      updater.setHardwareID("none"); 
      updater.setHardwareIDf("Device-%i-%i", 27, 46);
     
      // 将diagnostic任务添加到Updater中。它们将在调用Updater()函数时运行。
      //本质上, updater.add将传入内容转换为 DiagnosticTask。 
      //以下是两种添加的方法,任务的名称对应于任务的DiagnosticStatus的名称
       updater.add("Function updater", dummy_diagnostic);
       DummyClass dc;
       updater.add("Method updater", &dc&DummyClass::produce_diagnostics);
  
    
      //另外, FunctionDiagnosticTask 可以通过函数创建DiagnosticTask,
      //并且可以通过CompositeDiagnosticTask合并任务的输出,将 CompositeDiagnosticTask添加到Updater。
      //运行时总体名称将是子任务的名称, i.e., "Bound check". 
      
   diagnostic_updater::FunctionDiagnosticTask lower("Lower-bound check",
        boost::bind(&check_lower_bound, _1));
     diagnostic_updater::FunctionDiagnosticTask upper("Upper-bound check",
         boost::bind(&check_upper_bound, _1));
    
      diagnostic_updater::CompositeDiagnosticTask bounds("Bound check");
        bounds.addTask(&lower);
        bounds.addTask(&upper);
       updater.add(bounds);

    // 如果节点/处于特殊状态,则可以广播消息到所有的 DiagnosticStatus
         updater.broadcast(0, "Doing important initialization stuff.");
   
       ros::Publisher pub1 = nh.advertise<std_msgs::Bool>("topic1", 1);
    
       ros::Duration(2).sleep(); // 循环时间控制, 通过主函数中的ros::Duration(0.1).sleep()实现;
   
      // FrequencyStatus和TimestampStatus 是分别监视事件频率和时间戳的Diagnostic任务。
      // 对于没有header的消息,可以通过 HeaderlessTopicDiagnostic 处理FrequencyStatus (不能处理TimestampStatus)
      //或TopicDiagnostic可以处理FrequencyStatus 和TimestampStatus任务

    double min_freq = 0.5;
    double max_freq = 2;
    diagnostic_updater::HeaderlessTopicDiagnostic pub1_freq("topic1", updater, 
    diagnostic_updater::FrequencyStatusParam(&min_freq, &max_freq, 0.1, 10)); 
      // 注意TopicDiagnostic, HeaderlessDiagnosedPublisher,HeaderlessDiagnosedPublisher 以及 DiagnosedPublisher 
      //都派生自CompositeDiagnosticTask, 因此你可以通过addTask添加自己的任务。
       pub1_freq.addTask(&lower); // **(This wouldn't work if lower was stateful).**    
      // 每次更新pub1_freq时,lower也将得到更新,其输出将与pub1_freq的输出合并。
    
     // 如果知道节点状态改变,可以强制立即更新
      updater.force_update();       
     
     //删除任务
      if (!updater.removeByName("Bound check"))
     ROS_ERROR("The Bound check task was not found when trying to remove it.");
  
     while (nh.ok())
       {
        std_msgs::Bool msg;
        ros::Duration(0.1).sleep();
    
      // 对pub1的调用必须伴随对pub1_freq的调用,以保持最新的统计数据。
        msg.data = false;
        pub1.publish(msg);
        pub1_freq.tick();
    
      //可以在程序空闲时随时调用updater。函数本身将限制更新速度。
         updater.update();
      }
      return 0; 
       }
<think>我们正在处理一个关于CMake找不到`diagnostic_updater`包配置文件的问题。根据用户提供的引用信息,特别是引用[2]和引用[4],我们可以知道这个问题的典型原因和解决方法。 **问题分析**:当CMake执行`find_package(diagnostic_updater)`时,它会在一些特定路径下查找名为`diagnostic_updaterConfig.cmake`或`diagnostic_updater-config.cmake`的配置文件。如果找不到,就会报错。**可能的原因**: 1. `diagnostic_updater`包没有安装在系统的标准路径中。 2.环境变量`CMAKE_PREFIX_PATH`没有包含`diagnostic_updater`的安装路径。 3. `diagnostic_updater_DIR`变量没有设置为包含配置文件的目录。 **解决方法**:根据引用[2]和引用[4]的建议,我们可以采取以下步骤:###步骤1:确保`diagnostic_updater`已正确安装首先,确认你已经安装了`diagnostic_updater`包。在ROS中,可以使用以下命令安装:```bashsudoapt installros-<distro>-diagnostic-updater```其中`<distro>`是你的ROS发行版(如noetic、foxy等)。如果没有安装,请先安装。 ###步骤2:设置环境变量`CMAKE_PREFIX_PATH`如果已经安装了`diagnostic_updater`,那么需要将它的安装路径添加到`CMAKE_PREFIX_PATH`中。通常,ROS包的安装路径在`/opt/ros/<distro>`下。你可以通过以下方式设置: ```bashexport CMAKE_PREFIX_PATH=$CMAKE_PREFIX_PATH:/opt/ros/<distro>``` 然后重新运行CMake。###步骤3:设置`diagnostic_updater_DIR`变量如果上述方法无效,可以尝试直接设置`diagnostic_updater_DIR`变量,指向包含配置文件的目录。根据引用[4],配置文件通常位于`<package_install_dir>/share/<package_name>/cmake`目录下。对于`diagnostic_updater`,路径可能是:```/opt/ros/<distro>/share/diagnostic_updater/cmake```在CMakeLists.txt中,在`find_package`之前设置: ```cmakeset(diagnostic_updater_DIR"/opt/ros/<distro>/share/diagnostic_updater/cmake") ```或者在调用CMake时通过命令行参数设置:```bashcmake -Ddiagnostic_updater_DIR=/opt/ros/<distro>/share/diagnostic_updater/cmake.. ```###步骤4:确保ROS环境已配置在构建ROS相关项目时,确保已经source了ROS的setup.bash文件: ```bashsource /opt/ros/<distro>/setup.bash```###步骤5:检查CMakeLists.txt中的`find_package`调用确保在`find_package`调用中指定了必要的组件(如果有的话),例如: ```cmakefind_package(diagnostic_updaterREQUIRED) ```**总结**: 以上步骤应该能解决CMake找不到`diagnostic_updater`包配置文件的问题。如果问题仍然存在,请检查安装路径是否正确,以及是否有多个ROS版本导致路径冲突。§§相关问题§§1.如何查看已安装的ROS包所在的路径?2.在CMake中,`find_package`的工作原理是什么? 3.除了设置环境变量,还有哪些方法可以解决CMake找不到包的问题?</think>### CMake找不到diagnostic_updater包配置文件的解决方法 当CMake报错提示找不到`diagnostic_updaterConfig.cmake`或`diagnostic_updater-config.cmake`文件时,表明CMake无法定位diagnostic_updater包的配置文件。以下是系统性的解决步骤: #### 1. **确认包是否已安装** ```bash # 检查diagnostic_updater是否安装(ROS环境) dpkg -l | grep ros-*-diagnostic-updater # 或尝试重新安装 sudo apt install ros-<distro>-diagnostic-updater # 替换<distro>为实际ROS版本 ``` 若未安装,CMake自然找不到配置文件[^2]。 #### 2. **设置CMake搜索路径** 在CMakeLists.txt中**添加搜索路径**(在`find_package`前插入): ```cmake # 添加diagnostic_updater的安装路径 list(APPEND CMAKE_PREFIX_PATH "/opt/ros/<distro>/share") # 替换<distro> ``` 或通过**环境变量**设置: ```bash export CMAKE_PREFIX_PATH=$CMAKE_PREFIX_PATH:/opt/ros/<distro>/share ``` #### 3. **指定包目录变量** 在CMake命令中**显式指定路径**: ```bash cmake -Ddiagnostic_updater_DIR=/opt/ros/<distro>/share/diagnostic_updater/cmake .. ``` #### 4. **验证配置文件存在性** 手动检查配置文件是否存在: ```bash ls /opt/ros/<distro>/share/diagnostic_updater/cmake/ # 应看到 diagnostic_updaterConfig.cmake 文件 ``` 若不存在,可能是安装不完整[^4]。 #### 5. **检查ROS环境初始化** 确保已source ROS环境: ```bash source /opt/ros/<distro>/setup.bash # 编译前必须执行 ``` #### 6. **确认包命名一致性** 检查CMakeLists.txt中的包名是否**完全匹配**: ```cmake find_package(diagnostic_updater REQUIRED) # 名称必须与配置文件前缀一致 ``` > **原理说明**: > ROS包通过`catkin_package()`会在`/share/<pkg>/cmake`目录生成`<pkg>Config.cmake`文件,CMake的`find_package()`依赖此文件定位包[^4]。路径缺失或文件不存在会导致此错误。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值