Jump to content

DQMH - Does it make sense to have a "constant broadcast helper loop" and how do I prevent "circular messaging"?


Recommended Posts

Hey fancy folk,

 

I've been looking into the DQMH architecture a bit and I'm thinking about designing a test around it.  Basic test background, I am have a motor driving another motor and I'll be reading and writing over CAN for both motors and reading an analog in. I have laid out the basic module diagram as far as who is requesting what and who needs to broadcast their data.  I'm currently running into 2 issues that I'm someone can provide some insight on.

 

First Issues - constant broadcast helper loop

I will be have 3 read loops broadcasting their data to an "XY Module" (the data will get formatted in the XY style and stored in a circular buffer) which the XY module will broadcast the circular buffer to the "Main Module".  My issue is how do I do the constant read properly?  I have 2 basic ideas.  First is to create a helper loop that is started from the MHL and that helper loop continually broadcasts the message.  Second is to use the MHL timeout to do my read (set the timeout from -1 to say 100ms once the module is started).  IIRC, best practice is to have the helper loop do your repetitive actions, but by having my helper loop broadcast, I feel like I'm taking away from the main design that the MHL is supposed to broadcast.  I am currently leaning towards the second option since I'm not too worried if my read is a bit of.  For example, say another action got sent to the MHL (request sent to EHL which sends action to MHL) and the action takes 10 ms, the timing should be: read, wait X of 100 ms for MHL to receive action, do action in 10 ms, timeout 100 ms, read.  This would result in a 110+X ms between the reads.  I'm not worries about the 10+X ms between reads since my "test cycle" is on the side of 6 seconds.  I'm just trying to make sure I understand the drawback of method 2.

 

Second Issue - prevent circular messaging

I was reading about the best practices and they were saying that modules shouldn't have circular referencing.  In my project, I was going to have a set up of module A requests module B who broadcasts back to A and requests module C who broadcasts back to A.  I could go into more of the specifics if you want, but this is the basic idea.  Instead what I'm thining about is s Module A requests Module B, Module B broadcasts back to Module A, Module A sees the broadcast and sends the request to Module C.  In this scenario, Module A seems more like a "post office" for the messages/user events being sent back and forth.  I think its a bit cumbersome, but I also like how all the module controls stems from the "post office" since the submodules will only get their requests from the main module.

 

Any additional insight would be much appreciated,

Matt

Link to post

Hey Matt, great that you're looking into using DQMH!

Regarding your first question, I think you're using the term MHL (Message Handling Loop, the one in the bottom with the case structure) to describe the EHL (Event Handling Loop, the one on top with the event structure). 

You're saying that "by having my helper loop broadcast, I feel like I'm taking away from the main design that the MHL is supposed to broadcast". I don't think that by design only the MHL or EHL should do broadcasting. I would most definitely go with a helper loop. If you haven't seen it yet, feel free to take a look at our blog post on helper loops. It shows how to create helper loops that can be enabled/disabled.

Regarding your second issue, many people advocate to structure your modules like a tree, for exactly those reasons you already mentioned. You will find that as you remove the static dependencies, reusability of Modules B and C will pay for a little "cumbersomeness". 

Here's a graph illustrating that tree structure (I created it for another thread some time ago, so please excuse that the naming is different to yours) :

dqmh-tree_001.jpeg.e7dbe15818079152ef141f324a3bd84c.jpeg

Let me know if this helps!

Edited by joerghampel
  • Like 1
Link to post

I don't use DQMH myself, but some suggestions:

Re #1 and using the timeout: you don't need to use a fixed timeout; you can write some small subVI that calculates the time remaining till the next scheduled read.  For example, if teh last Read was at 98700 ms, the next read should happen at 98800 ms.  If it is now 98712 ms, then the subVI can output a 88 ms timeout.  If a message is handled, and the time is now 98798 ms, then the subVI will calculate a timeout of 2 ms.   You would code in logic of what to do if it is after the scheduled time (either do anyway, or skip).

Re #2: you could have the higher-level Module A send a message to C  containing the User Event of B's Broadcast.  Then C can listen to B, without directly referencing it.  B and C would need to agree on the datatype of the User Event, but would not otherwise be coupled.  A is doing the coupling, but without handling all the messages.

  • Like 1
Link to post

Concerning coupling related to DQMH modules, keep in mind that:

- When module A broadcast data and module B is registered to this broadcast. Module A is not coupled to module B

- When a module B uses a request or is registered to a broadcast from module A, Module B is coupled to module A

With that in mind, it's easier to detect where the coupling is.

Basically, your "low level" modules should be decoupled from the high-level modules. High-level modules are projects related and low-level modules could be used in any project.

 

  • Like 1
Link to post
On 5/20/2021 at 12:34 PM, drjdpowell said:

Re #2: you could have the higher-level Module A send a message to C  containing the User Event of B's Broadcast.  Then C can listen to B, without directly referencing it.  B and C would need to agree on the datatype of the User Event, but would not otherwise be coupled.  A is doing the coupling, but without handling all the messages.

drjdpowell,

I don't think I understand what you are saying.  All I can think of is rebroadcasting the data vs broadcasting the user event to.

To give some details, A is the "post office" handling user events between B and C.  B has a helper loop reading XNET as an XY and C is the test's state machine. Since C is expecting the XNET type of XY, B would broadcast it's XY to A, then A would rebroadcast that XY to C.  In this case A is just forwarding the user event from B to C without actually doing any work on it.

On 5/19/2021 at 6:04 PM, joerghampel said:

Hey Matt, great that you're looking into using DQMH!

Regarding your first question, I think you're using the term MHL (Message Handling Loop, the one in the bottom with the case structure) to describe the EHL (Event Handling Loop, the one on top with the event structure). 

You're saying that "by having my helper loop broadcast, I feel like I'm taking away from the main design that the MHL is supposed to broadcast". I don't think that by design only the MHL or EHL should do broadcasting. I would most definitely go with a helper loop. If you haven't seen it yet, feel free to take a look at our blog post on helper loops. It shows how to create helper loops that can be enabled/disabled.

joerghampel,

I thought the EHL was the "top loop" that listens to user events or button presses via the event loop.  The EHL would then send a message via queue to the "lower loop" of the MHL which would then be the primary place where you "do the work" of the module. 

Regrading the helper loop reccomendation, it sounds like the helper loop would be triggered by the user events of a different module...?  The way that I have been imagining the helper loop, it would set some timeout/flag to start and stop the module via the EHL getting a request to start broadcasting which sends a message to the MHL to set the flag to initialize the helper loops.  Likewise when the code needs to stop, the EHL sends a message to MHL which sends the flag to the helper loop.  This feels a bit cumbersome, but thats how I am currently visualizing the process.

Link to post
18 hours ago, Matt_AM said:

I thought the EHL was the "top loop" that listens to user events or button presses via the event loop.  The EHL would then send a message via queue to the "lower loop" of the MHL which would then be the primary place where you "do the work" of the module. 

Exactly, what you say here is correct. I was confused by your suggestion to "use the MHL timeout" - but I realise now you actually meant to change the timeout setting for reading from the message queue in Delacor_lib_QMH_Dequeue Message.vi, right?

That could be done by implementing your own child class for the default DQMH Message Queue class and overriding that method. While there definitely are proper use cases for implementing your own child class of the Message Queue, I don't think this is one. I would advise against going down that rather unusual road when there are simpler solutions available. 

 

18 hours ago, Matt_AM said:

Regrading the helper loop reccomendation, it sounds like the helper loop would be triggered by the user events of a different module...?  The way that I have been imagining the helper loop, it would set some timeout/flag to start and stop the module via the EHL getting a request to start broadcasting which sends a message to the MHL to set the flag to initialize the helper loops.  Likewise when the code needs to stop, the EHL sends a message to MHL which sends the flag to the helper loop.  This feels a bit cumbersome, but thats how I am currently visualizing the process.

You can make your helper loop private (then the only way to control it from outside the module is to go through EHL and MHL, just as you describe).

Or, you can design your helper loop to contain an event structure, and make it publicly available by registering for (some of the) DQMH module's request events directly in the helper loop's event structure. This is the design we describe in our blog post on helper loops.

Link to post

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.