About the two kinds of ROS Time that will appear in ROS

During the experiment, it is found that ROS actually counts two ROS times

  • One is the simulation time: sim time, which should be calculated only when the program is started
  • One is the system time: system time, which should match the system time

Many people may not know much about these two times. It should be considered in many places. The system will help us deal with their relationship.

At the same time, the functions that read them are the same, ros::Time::now()
If you pay attention, you will find that the update frequency of some nodes is a series of long time numbers, while the update frequency of some nodes is a lot of time, which shows that one node reads the system time and the other reads the SIM time. Therefore, the time of these two nodes can be said to be different.
In the general application process, the above problems can be ignored only when publishing and receiving information through topic without considering ros time. However, when some nodes need to make planning, they need to calculate according to the data corresponding to ros time. At this time, if one of the ros time is system time and the other is sim time, there will be a problem, Because the system time is a large group of numbers, it will think that sim time belongs to a very long value, and then an error will be reported. For example, 1631889779.809762075 is the system time and 42.56851 is sim time. In this case, even if we know that the two times are equal in meaning, the two numbers are very different in value.

To solve this problem, you can check whether you have started the simi time of gazebo, as follows:

  <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>

There is a parameter called use_sim_time. If you select true, it will publish sim time. If you do not use system time, if you select false, it will become system time.

Knowing this option can solve some problems.

However, if someone uses the joint controller of ROS, as shown below.

 <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"/> 

At this time, you will find that whether you turn off or turn on the SIM time of gazebo, it has no impact on it. It always uses SIM time, which is disgusting. If the system time is selected in gazebo and the joint controller uses SIM time, it will lead to the robot state publisher robot_ state_ The TF relationship published by publisher is also SIM time, which leads to TF error. If you can't connect, TF will make an error, resulting in the robot unable to display normally, as shown in the figure below

As can be seen from the figure, the system time is used at the top, a long string of numbers, but the update time at the lower joints, first link, second link and arm link, is sim time, which is a small value. If the two times do not match at all, the robot will not be able to display normally in rivz.

Therefore, the solution is not to use the joint controller provided by ROS, but to write a joint state publisher to maintain the joint state information. Of course, the joint state publisher should also consider that it cannot release the state only after receiving the instruction, and it should always release the joint information when it does not receive the instruction.

The following is a simple version of the joint state publisher. The full version will be updated next week:

#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;
}


The above is my personal understanding. If there is a great God with more accurate information, please comment and comment.

Reference

  1. ROS learning notes (XVI): Using urdf with robot_state_publisher:
    https://blog.csdn.net/qq_42910179/article/details/107038351

Tags: ROS

Posted on Sun, 19 Sep 2021 12:02:41 -0400 by jonah