关于在ROS中会出现的两种ROS Time

做实验的过程中发现,ROS里面其实会计算两个ROS Time

  • 一个是仿真的时间:sim time,这个时间应该是从启动程序时才开始计算的
  • 一个是系统的时间:system time,这个应该跟系统的时间是match的

这两个时间,很多人可能没有怎么了解,应该确实很多地方也需要考虑到它,系统内部会帮忙我们处理好它们的关系。

同时,读取它们的函数都是同一个,ros::Time::now()
如果有留意的话,会发现,有些节点的更新频率是一串很长的时间数字,有些节点的更新频率却是很多的一个时间,这就说明一个节点读取的是系统时间,另一个读取的是SIM time,所以这两个节点的时间其实可以说是不一样的。
在一般应用过程中,只是通过topic发布信息,和接收信息,不考虑ros time的情况下,可以忽略上面的问题,但是有些节点要做规划的时候,需要根据ros time对应的数据来做计算,这时这个ros time如果一个是系统时间另一个是sim time就会出问题,因为系统时间是很大的一组数,它会认为sim time是属于它很久远的一个数值,然后就会报错,如1631889779.809762075是系统时间,42.56851是sim time,这种情况下,即使我们知道它们两个时间在含义上是对等的,但在数值上,这两个数就相差很远很远了。

要处理这个问题,可以看看自己是否启动了gazebo的simi time,如下:

  <include file="$(find gazebo_ros)/launch/empty_world.launch">
    <arg name="world_name" value="worlds/empty.world"/>
    <arg name="debug" value="$(arg debug)" />
    <arg name="gui" value="$(arg gui)" />
    <arg name="paused" value="false"/>
    <arg name="use_sim_time" value="true"/>
    <arg name="headless" value="$(arg headless)"/>
  </include>

里面有一个参数名叫use_sim_time,如果选true,它就会发布sim time,不使用系统时间,选false就会变为系统时间。

知道这个选项后就可以解决部分问题。

但是如果有人使用的是ROS自带的关节控制器,如下所示。

 <node name="controller_spawner" pkg="controller_manager" type="spawner" respawn="false"
	output="screen" ns="/mobile_manipulator" args="joint_state_controller
					  first_joint_position_controller second_joint_position_controller third_joint_position_controller"/> 

这时会发现,不管是关闭或选择开启gazebo的sim time,对它都是没有影响的,它一直使用SIM time,这就很恶心了,如果gazebo中选了系统时间,而这个关节控制器使用的是sim time,就会导致机器人状态发布器robot_state_publisher发布的TF关系也是sim time,这就导致TF报错,无法连接上,TF就会出错,导致机器人无法正常显示,如下图所示
ros time

从图中可以看出,最顶端用的是系统时间,一串很长的数,但是下方的关节处,first link 和 second link以及arm link那里更新的时间是sim time,很小的值,这两个时间完全match不上,就会导致机器人没办法正常在rivz中显示。

所以要解决的方案是,不使用ROS自带的这个关节控制器,而是自己写一个关节状态发布器,来维护关节的状态信息。当然这个关节状态发布器也要考虑到,不能只是收到指令才发布状态,在没有收到指令时也要一直发布关节信息。

以下是一个简易版的关节状态发布器,下周再更新完整版的:

#include <string>
#include <ros/ros.h>
#include <sensor_msgs/JointState.h>
#include <tf/transform_broadcaster.h>

int main(int argc, char** argv) {
    ros::init(argc, argv, "state_publisher");
    ros::NodeHandle n;
    ros::Publisher joint_pub = n.advertise<sensor_msgs::JointState>("/mobile_manipulator/joint_states", 1);
    tf::TransformBroadcaster broadcaster;
    ros::Rate loop_rate(100);

    // message declarations
    sensor_msgs::JointState joint_state;

/**/
    double num = 1;
    while (ros::ok()) {
        //update joint_state
        num++;

        joint_state.header.stamp = ros::Time::now();
        joint_state.name.resize(3);
        joint_state.position.resize(3);
        joint_state.name[0] ="first_joint";
        joint_state.position[0] = num*0.01;
        joint_state.name[1] ="second_joint";
        joint_state.position[1] = num*0.01;
        joint_state.name[2] ="third_joint";
        joint_state.position[2] = num*0.01;
 
        joint_pub.publish(joint_state);


        // This will adjust as needed per iteration
         loop_rate.sleep();
    }

    // joint_state.header.stamp = ros::Time::now();
    // joint_state.name.resize(3);
    // joint_state.position.resize(3);
    // joint_state.name[0] ="first_joint";
    // joint_state.position[0] = 0;
    // joint_state.name[1] ="second_joint";
    // joint_state.position[1] = 0;
    // joint_state.name[2] ="third_joint";
    // joint_state.position[2] = 0;

    // joint_pub.publish(joint_state);
    // ros::spin();
 
    return 0;
}


以上都是个人的理解,如果有大神有更准确的信息,请评论留言指正。

Reference

  1. ROS学习笔记(十六):Using urdf with robot_state_publisher:
    https://blog.csdn.net/qq_42910179/article/details/107038351
  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ROS中,`waitForTransform()`函数是TF库中的一个函数,用于等待两个帧之间的转换可用。它通常用于等待两个帧之间的转换被广播,以便您可以使用`lookupTransform()`函数来查询它们之间的转换。 这个函数的语法如下: ```cpp bool tf_listener.waitForTransform(const std::string& target_frame, const std::string& source_frame, const ros::Time& time, const ros::Duration& timeout, const ros::Duration& polling_sleep_duration); ``` 其中,`target_frame`和`source_frame`是要查询的两个帧的名称,`time`是您想要查询的时间戳,`timeout`是等待时间的最大值,`polling_sleep_duration`是每次查询之间的休眠时间。 如果转换在超时之前变得可用,则函数将返回`true`,否则将返回`false`。 以下是一个使用`waitForTransform()`函数的示例代码,用于等待`base_link`和`laser_link`帧之间的转换: ```cpp #include <tf/transform_listener.h> #include <ros/ros.h> int main(int argc, char** argv) { ros::init(argc, argv, "tf_listener"); ros::NodeHandle nh; tf::TransformListener tf_listener; std::string target_frame = "base_link"; std::string source_frame = "laser_link"; ros::Time time = ros::Time(0); ros::Duration timeout = ros::Duration(5.0); bool success = tf_listener.waitForTransform(target_frame, source_frame, time, timeout, ros::Duration(0.01)); if (success) { ROS_INFO("Transform from %s to %s is available", source_frame.c_str(), target_frame.c_str()); } else { ROS_ERROR("Failed to get transform from %s to %s", source_frame.c_str(), target_frame.c_str()); } return 0; } ``` 在这个例子中,我们将等待5秒钟来获取`base_link`和`laser_link`帧之间的转换,并在转换可用时输出一条消息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值