0
$\begingroup$

Rosanswers logo

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();
}

Originally posted by PatFGarrett on ROS Answers with karma: 31 on 2020-01-30

Post score: 0


Original comments

Comment by Delb on 2020-01-30:
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.

Comment by PatFGarrett on 2020-01-30:
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

$\endgroup$

1 Answer 1

0
$\begingroup$

Rosanswers logo

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.


Originally posted by gvdhoorn with karma: 86574 on 2020-01-30

This answer was ACCEPTED on the original site

Post score: 0


Original comments

Comment by PatFGarrett on 2020-01-30:
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();

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.