Advanced: Redirecting Module Output to Stand-Alone Message
Consider a more advanced Basilisk simulation setup where you have two modules that both need to write to the same stand-alone message. The motivation here is to simultaneously run two or more flight guidance algorithm modules, but only one gets executed depending on the flight mode. Regardless of which guidance module is executed, the guidance output message must be fed to the same control module. This cannot be accomplished if the third module subscribes either to the output message of module 1 or 2. To avoid trying to re-subscribe to different module output messages when switching flight modes, we can choose to have both modules 1 and 2 write to the same stand-alone message as illustrated below.
The benefit is that the 3rd module can subscribe its input message to this one stand-alone message. To be clear, this sample application assumes either module 1 or 2 is executed, but not both. Otherwise, one would overwrite the others’ message output.
The sample simulation script creates both a C and C++ module which have their individual output messages redirected to a stand-alone message. The process is different for both programming languages.
Warning
Basilisk C modules contain C wrapped message objects and thus can only write to a stand-alone C wrapped message interface. Similarly, a C++ module contains C++ message objects and can only write to a C++ stand-alone message. You can’t have a C module write to a C++ stand-alone message.
In the following sample code, a C and C++ Basilisk module are created. To create a C wrapped stand-alone
message the messaging
package must be imported from Basilisk.architecture
. Next, assume a message
of type SomeMsg
needs to be created. This is done using:
cStandAloneMsg = messaging.SomeMsg_C()
cStandAloneMsg.write(messaging.SomeMsgPayload())
Be sure to provide an empty payload structure to the C-wrapped message object. Otherwise a read()
operation on this stand-alone msg object will cause a segmentation fault.
To enable a C module someCModule
to redirect its output message dataOutMsg
writing to this stand-alone
message use:
messaging.SomeMsg_C_addAuthor(someCModule.dataOutMsg, cStandAloneMsg)
Now the module someCModule
will not write to its own internal output message, but rather it will write into this stand-alone message.
1
2from Basilisk.architecture import messaging
3from Basilisk.moduleTemplates import cModuleTemplate
4from Basilisk.moduleTemplates import cppModuleTemplate
5from Basilisk.utilities import SimulationBaseClass
6from Basilisk.utilities import macros
7
8
9def run():
10 """
11 Illustration of re-directing module output message to stand-alone messages
12 """
13
14 # Create a sim module as an empty container
15 scSim = SimulationBaseClass.SimBaseClass()
16
17 # create the simulation process
18 dynProcess = scSim.CreateNewProcess("dynamicsProcess")
19
20 # create the dynamics task and specify the integration update time
21 dynProcess.addTask(scSim.CreateNewTask("dynamicsTask", macros.sec2nano(1.)))
22
23 # create modules
24 mod1 = cModuleTemplate.cModuleTemplate()
25 mod1.ModelTag = "cModule1"
26 scSim.AddModelToTask("dynamicsTask", mod1)
27
28 mod2 = cppModuleTemplate.CppModuleTemplate()
29 mod2.ModelTag = "cppModule2"
30 scSim.AddModelToTask("dynamicsTask", mod2)
31
32 # create stand-alone message with a C interface and re-direct
33 # the C module output message writing to this stand-alone message
34 cMsg = messaging.CModuleTemplateMsg_C()
35 cMsg.write(messaging.CModuleTemplateMsgPayload())
36 messaging.CModuleTemplateMsg_C_addAuthor(mod1.dataOutMsg, cMsg)
37
38 # create stand-along message with a C++ interface and re-direct
39 # the C++ module output message writing to this stand-alone message
40 cppMsg = messaging.CModuleTemplateMsg()
41 mod2.dataOutMsg = cppMsg
42
43 # initialize Simulation:
44 scSim.InitializeSimulation()
45
46 # configure a simulation stop time and execute the simulation run
47 scSim.ConfigureStopTime(macros.sec2nano(1.0))
48 scSim.ExecuteSimulation()
49
50 # read the message values and print them to the terminal
51 print("mod1.dataOutMsg:")
52 print(mod1.dataOutMsg.read().dataVector)
53 print("cMsg:")
54 print(cMsg.read().dataVector)
55 print("mod2.dataOutMsg:")
56 print(mod2.dataOutMsg.read().dataVector)
57 print("cppMsg:")
58 print(cppMsg.read().dataVector)
59
60 return
61
62
63if __name__ == "__main__":
64 run()
For the C++ Basilisk module it is simpler to re-direct the output message. The stand-alone message is created as before:
cppStandAloneMsg = messaging.SomeMsg()
To redirect the output of a C++ module someCppModule
to this stand-alone message, simply set:
someCppModule.dataOutMsg = cppStandAloneMsg
Note
If you want to record the output of someCModule
be sure to record cStandAloneMsg
instead of someCModule.dataOutMsg
. The later is no longer being written to
unless you use the .read()
method which sync’s up the payload content. In C++
we are setting cppStandAloneMsg
equal to someCppModule.dataOutMsg
. Here recording either
will give the same result.
To see the message states of both the module internal message objects and the stand-alone messages,
the sample script shows how to use .read()
to read the current state of the message object.
This will return a copy of the message payload structure. The same method can be used to access both
C and C++ wrapped messages. For the C-wrapped message object, the .read()
command will also copy
the content from the stand-alone message to the module message. This is why the .read()
command
below on the module output message returns the correct value.
After executing the script you should see the following terminal output:
source/codeSamples % python bsk-7.py
BSK_INFORMATION: Variable dummy set to 0.000000 in reset.
BSK_INFORMATION: Variable dummy set to 0.000000 in reset.
BSK_INFORMATION: C Module ID 1 ran Update at 0.000000s
BSK_INFORMATION: C++ Module ID 2 ran Update at 0.000000s
BSK_INFORMATION: C Module ID 1 ran Update at 1.000000s
BSK_INFORMATION: C++ Module ID 2 ran Update at 1.000000s
mod1.dataOutMsg:
[2.0, 0.0, 0.0]
cMsg:
[2.0, 0.0, 0.0]
mod2.dataOutMsg:
[2.0, 0.0, 0.0]
cppMsg:
[2.0, 0.0, 0.0]