lcm-proj / lcm

Lightweight Communications and Marshalling
GNU Lesser General Public License v2.1
997 stars 393 forks source link

Question on good lcm practices #244

Open andrea-nisti opened 6 years ago

andrea-nisti commented 6 years ago

I worked extensively with LCM for the past three years but I have a question about one code practice that maybe I am doing wrong.

If I want to subscribe to multiple topics and I want to monitor the incoming messages with a POLL, do I need to build one lcm handler for each topic? Here's an example of what I am doing right now: https://github.com/EmaroLab/mocap2mav/blob/master/modules/Automatic/src/main.cpp#L12

Is this the way of implementing a subscriber "node" that reads from multiple channels (asynchronously)?

FYI that is a software for autonomous navigation and automatic landing for a quadcopter, I developed it entirely thanks to LCM and since I am here writing I take this opportunity to thank the entire community and the developers.

tprk77 commented 6 years ago

Sorry for the delayed response, but you should only ever need one LCM object. You can call subscribe on the same LCM object any number of times, there is no restriction on that.

As a side note, I would not call the LCM a "handler". (You can think of it more as a "dispatcher" probably.) I would refer to the callbacks provided to subscribe as the message handlers. What the LCM object does is, it receives all the LCM messages, and then during LCM::handle, for each message, it looks up all the relevant subscribers based on the channel, and then it it invokes the callback of each subscriber with the message. Hopefully that helps.

andrea-nisti commented 6 years ago

Hello, thanks for the response. What if I need to check multiple incoming topics in a non-blocking style? I do it with the poll function but I need a file descriptor for each topic, this is why I use multiple handlers. How can I correct this?

tprk77 commented 6 years ago

Your main problem is that you have not isolated your message handling logic to your subscription callbacks. You have added some extra logic around calling LCM::handle to augment your message handling, and as you have already found out, this is causing you some issues with blocking execution.

The LCM object itself is not a handler. All of your message handling logic should be in the subscription callbacks. Looking at your code again, I would suggest some refactoring. For example, this block:

autom.setTask(call._task);
std::cout<<  "New task arrived with action: " ...;
waiting = false;
autom.handleCommands();

This code should move to inside the CallbackHandler::actualTaskCallback function.

Once you have moved all the code into the callbacks, then you can just use one LCM object, and only have one call to LCM::handle. There is no need to have multiple LCM objects. I would actually say it's best to avoid that, because it's a bit redundant and uses extra resources.

andrea-nisti commented 6 years ago

Thanks for the detailed answer! I'll update as soon as I can.

My question now is how can I implement a structure with a main loop, that runs at a fixed rate for example, plus adding non-blocking calls from multiple subscriptions? For example, imagine an architecture where I have to send messages with a fixed rate and perform some operation when a sporadic topic is updated, I don't want to be blocked until a message arrives. But yeah, I get what you mean in you previous comment.

I hope I was clear enough, thanks again!