robotology / blockfactory

A tiny framework to wrap algorithms for dataflow programming
https://robotology.github.io/blockfactory
GNU Lesser General Public License v2.1
40 stars 16 forks source link

Suggestion for configuring Size And Ports into Initialize phase #51

Open DavideAntonucci opened 4 years ago

DavideAntonucci commented 4 years ago

Hi all,

My colleagues (@liesrock @alaurenzi) and I are working with the blockfactory to use our framework in Matlab/Simulink.

Is there a possibility to declare a size port during the initialize phase?

Since I use the configureSizeAndPorts method to declare my inputs and outputs with a dynamic size port and I know the size after the initialize phase, I was wondering if there is a chance to do it in this phase.

Davide.

diegoferigo commented 4 years ago

Hi @DavideAntonucci

TL;DR No, if you want to fix signal sizes, you have to know them in the configureSizeAndPorts.

Is there a possibility to declare a size port during the initialize phase?

Since I use the configureSizeAndPorts method to declare my inputs and outputs with a dynamic size port and I know the size after the initialize phase, I was wondering if there is a chance to do it in this phase.

Before running a simulation, Simulink performs a series of predefined steps to prepare the DAG that describes the execution order of the blocks. You can read more at this link.

To answer your question, you need to know that the Block methods relevant during initialization are mapped as follows with the Simulink Engine:

These two steps are completely independent. This means that, as documented, all the block resources configured / allocated in configureSizeAndPorts get deleted. In fact, a temporary Block object is created and destroyed afterwards. What's important is that in this phase Simulink performs something similar:

  1. Get all the ports with fixed-size signals and checks for incompatibilities
  2. Get all the dynamic signals and tries to propagate / guess signal size
  3. Creates the DAG with the resulting block connections and their signal size

If Simulink cannot figure out the signal size, it fails with an error and does not continue. This is not so unlikely if you're writing your own blocks. In fact, if you overuse dynamic size, it might happen that Simulink is not able to finalize the size propagation.

This is more or less what happens under the hood in the first phase of the simulation, or also when you press Ctrl+D.

Despite it is not forbidden to call in the mdlStart phase the methods that operate on signal sizes, if I recall well, they do not work (and no warning / error is issued). The next mdlStart phase expects to have already the information about the signal size and the only thing you might want to do in this step is to add few checks that sizes are what expected (example QpOases.cpp).

alaurenzi commented 4 years ago

Hi @diegoferigo, thanks for your time. This would not be a problem for us, but, if I understood correctly from @DavideAntonucci, the mdlInitializeSizes (implying Block::configureSizeAndPorts) is also called when a new block is dropped to the simulink panel. Maybe this is related to the following note in the Simulink documentation that you linked before:

Note
The mdlInitializeSizes callback method also runs when you enter the name of a compiled S-function into the S-Function Block Parameters dialog box.

Now, when a block is dropped, we have no idea about the ports size, because they depend on the URDF which, in out context, could not be available until the play button is pressed. Have you experienced this problem as well?

traversaro commented 4 years ago

Now, when a block is dropped, we have no idea about the ports size, because they depend on the URDF which, in out context, could not be available until the play button is pressed. Have you experienced this problem as well?

I guess @diegoferigo can answer with more details, but in the meanwhile I think I can answer that in the WB-Toolbox case the URDF and the list of controller joints is assumed to be known at that stage, as you can see in the case of a block such as the one that computes the Jacobian:

diegoferigo commented 4 years ago

Maybe this is related to the following note in the Simulink documentation that you linked before:

The mdlInitializeSizes callback method also runs when you enter the name of a compiled S-function into the S-Function Block Parameters dialog box.

It could be, I think it is used to update the mask I/O appearance as soon as you drop the block in a model.

Now, when a block is dropped, we have no idea about the ports size, because they depend on the URDF which, in out context, could not be available until the play button is pressed. Have you experienced this problem as well?

As @traversaro wrote, blocks belonging to our WBToolbox have access to the URDF already from the configureSizeAndPorts method. In this way we can avoid using ports with dynamic size. This is particularly important because blocks that read robot measurements (e.g. joint positions) are typically input blocks. Fixing the size of their output signal simplifies a lot the process of understanding signal sizes of the overall Simulink model.

In your case, if the URDF is only available when you press the play button, means that you have access to its data starting from the mdlStart / Block::initialize phase. How do you pass the URDF file to the block? As a mask parameter?

Right now I don't see any solution that does not involve moving the URDF parsing to the configureSizeAndPorts step, unless you find a way to handle your problem with dynamically-sized ports.

traversaro commented 4 years ago

The following Simulink functions to define "accepted" values for dynamically sized ports seems to be interesting:

depending on when they are called, implementing in some way support for calling them in BlockFactory could solve this problem. Anyone has experience with them? Another interesting function is mdlSetDefaultPortDimensionInfo ( https://www.mathworks.com/help/simulink/sfg/mdlsetdefaultportdimensioninfo.html ).

An interesting project (similar to BlockFactory) that implements them is EasyLink, see: https://github.com/gjlaurent/easylink/blob/8aecaf915a827522aa73d0f64b894810849570e9/include/sfunDefinitions.h#L32

Also this piece of code seems to be related, and I guess @alaurenzi should be familiar with it : ) : https://github.com/ADVRHumanoids/XBotMatlabInterface/blob/f66202b0844375fb2d38e9b581f7bb00d5e40742/gcomp_example.cpp#L109 .

diegoferigo commented 4 years ago

@traversaro I remember I played a bit with those methods in order to solve propagation problems we faced in the past, without any luck unfortunately. I recall that I couldn't make them work as expected, not sure if it was my fault of using them in the wrong way.

An interesting project (similar to BlockFactory) that implements them is EasyLink

This is extremely interesting. We should have a look if they support also variable step solvers and other cases we did not yet implement.

traversaro commented 4 years ago

@traversaro I remember I played a bit with those methods in order to solve propagation problems we faced in the past, without any luck unfortunately.

I am not sure, but I think the propagation problems that you had are not exactly the same as just declaring some port as dynamic and specifying their values after the initialization, as discussed in this issue.

traversaro commented 4 years ago

This discussion can be related: https://github.com/robotology/wb-toolbox/issues/97 .

DavideAntonucci commented 4 years ago

Hi all,

About this issue, we found a possible solution that consist to Configure Size and port in this way:

Since we need to have the ROS Master and XBotCore Node alive to get, for instance, the joint number, during the configure size and port phase we check:

1) ROS Master and XBotCore Node alive.

Then if the first step that it's checked by the Initialize phase too, is not satisfied, the Initialize method will print the error.

This allows us to develop the libraries without having errors, as soon as the play button is pressed, all checks will be performed.