ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange
Ask Your Question
0

Accessing a subscribers data at a different rate

asked 2020-01-29 23:39:02 -0600

PatFGarrett gravatar image

updated 2020-01-30 08:45:32 -0600

Hello, thanks for any and all responses, but simply:

I am running a control loop that generates and publishes new velocities at 100hz, every-time it calculates a new velocity it needs the current motor shaft position data. However, this position data is subscribed To and arriving at a much higher rate than the control is running.

How can I/best method for accessing the current data from this subscribed to topic at the moment I need it in the control loop?

An example:

ros::Subscriber pointSub;
ros::Subscriber posSub;

float phi = 0.0;     /// a global variable that gets updated 


void controlLoop(const geometry_msgs::Point & currentPoint) {
  //RUNS ONCE!!! triggered by arriving x,y,z point data

  ros::Rate rate(100)
  for(int i = 0 ; i < 100; i++)
  {

      //HERE I WANT THE UPDATED, most recent, PHI VALUE

      ros::spinOnce();
      rate.sleep();
  }

} //END OF control loop

void fastPositionCb(const std_msgs::Float64 currPos) {
  //Gets data published faster than 100hz .... say 1kHz

  phi = CurrPos.data;

}

int main(int argc, char * argv[]) {
  ros::init(argc, argv, "example");
  ros::NodeHandle nh;

  pointSub = nh.subscribe("testPoint", 1, controlLoop);  // happens once
  posSub = nh.subscribe("phiPos", 1, fastPositionCb);   // happens very fast

  // Spin
  ros::spin();
}
edit retag flag offensive close merge delete

Comments

I'm not sure to fully understand what you want to achieve. Do you want to call the controlLoop callback faster than the fastPositionCb or only with the latest data received ?

Anyway I would change your code to have your callbacks only receiving the data and assigning it to some global variables (or better using classes) because looping in a callback is really not adivised, you should only do simple operations inside callbacks to ensure you receive all the messages. So the main would have a loop like this :

ros::Rate rate(YOUR_DESIRED_RATE)
while (ros::ok())
{
    //Do what you need to with the data you received
    ros::spinOnce();
    rate.sleep();
}

Correct me if I misunderstood your issue I'll correct my suggestion accordingly.

Delb gravatar image Delb  ( 2020-01-30 02:20:42 -0600 )edit

Delb, Thanks for the response, and I apologize for not being very clear. But you are basically right... I want To harness the data coming in from a very fast topic and use it at a a rate of 100Hz. I adjusted my sample code To hopefully show this better

PatFGarrett gravatar image PatFGarrett  ( 2020-01-30 08:39:54 -0600 )edit

1 Answer

Sort by ยป oldest newest most voted
0

answered 2020-01-30 10:11:39 -0600

gvdhoorn gravatar image

Based on your edit I would suggest to look into message_filters, specifically the Cache class.

From the wiki page:

Stores a time history of messages.

Given a stream of messages, the most recent N messages are cached in a ring buffer, from which time intervals of the cache can then be retrieved by the client. The timestamp of a message is determined from its header field.

So whenever you receive a message on the "slow" stream, look into your Cache and retrieve the message from the fast stream that corresponds to the same header.stamp.

If you'd like to automate this process you could even use a policy-based synchronizer, probably the ApproximateTime Policy. This will allow you to register a callback which will only be called when there are matching messages in both datastreams.

You might have to play with the buffer and/or slack time, depending on how disparate the two message rates are.

edit flag offensive delete link more

Comments

Gvdhoorn,

Hello and thank you for response. If i understand your answer and what I read about message_filters is that they create a que of messages as they arrive. So I would fill that up with my "fast topic" and then as my slow function needs it i just pick off the top? The only issues I see is does this make them run in parallel? Will i be able To access the fast channels que at any given time... I guess ya that makes sense, if there isnt a brand new message it will get the ques top/last item.

Ultimately in my "slow loop" i want To call something that, although hypothetically, would look like this:

data = some_subscriber.getTopicDataNow();

PatFGarrett gravatar image PatFGarrett  ( 2020-01-30 15:12:41 -0600 )edit

Question Tools

2 followers

Stats

Asked: 2020-01-29 23:39:02 -0600

Seen: 258 times

Last updated: Jan 30 '20