C Module: cModuleTemplate
Executive Summary
The C module template demonstrates message handling, a simple vector calculation, reset behavior, and variable logging. On every update, it copies an optional input vector and adds an increasing counter to the first component. It is a working starting point for new C modules; C++ Module: cppModuleTemplate implements the same example in C++.
This page also serves as an example of module documentation. See Module RST Documentation for the RST authoring tutorial, including equations, figures, tables, and code blocks.
Module Assumptions and Limitations
The calculation is an instructional example with dimensionless vectors and a dimensionless counter. It does not model a physical system. The counter advances once per scheduled update, independently of the task period. No configuration is required to run the module.
The input is optional. When connected, the module uses the latest message payload; it does not check its age or whether the publisher has written a new value since the last update. When disconnected, the input vector is zero.
Message Connection Descriptions
Connect the input from Python using subscribeTo(). Both messages use the three-element
dataVector field of CModuleTemplateMsgPayload.
Msg Variable Name |
Msg Type |
Description |
|---|---|---|
dataInMsg |
Optional dimensionless input vector. Uses a zero vector when disconnected. |
|
dataOutMsg |
Dimensionless input vector with the update counter added to its first component. Reset publishes a zero vector; each update publishes the calculated vector. |
Detailed Module Description
Let \(\mathbf{x}_k\) be the input vector at update \(k\), \(c_k\) the counter, and \(\mathbf{y}_k\) the output. After reset, \(c_0 = 0\); the first update is \(k = 1\). Each update computes
For a disconnected input, \(\mathbf{x}_k = \mathbf{0}\) and the output is
\([c_k, 0, 0]^T\). The implementation demonstrates v3SetZero() and v3Copy()
from linearAlgebra, and zeroes the output payload before populating it.
SelfInit() initializes the C output message. Reset() clears the counter and writes
a zero output payload at the reset time. It preserves the sample configuration vector.
The next update starts the counter at one and evaluates Eq. (1).
Configuration and Runtime State
Configuration holds values supplied by the user, while runtime state holds values the module updates as the simulation runs. The C configuration structure contains both kinds of data; all its members are public. The sample variables in the C and C++ templates have these roles:
updateCounteris a dimensionless runtime counter.Reset()clears it, including any value assigned beforeInitializeSimulation(). Each update increments it and adds it to the first component of the input vector to form the output. The C++ setter demonstrates scalar validation and access.sampleConfigVectoris a dimensionless sample configuration vector used to demonstrate assignment and variable logging. Resets and updates preserve it, and it does not affect the output calculation. Python-created modules default this vector to zero; the C++ setter requires positive components when used.inputVectoris scratch storage for the current input. Each update overwrites it with the connected input vector or zeros if the optional input is disconnected. C stores it in the module structure; C++ uses a local array.
See Setting and Recording Module Variables for an example of recording the counter and the sample vector.
User Guide
The following complete script runs three updates, at 0, 0.5, and 1 second, and checks the
output vectors. Add the recorder after the module so it samples the newly written output
at each task time. InitializeSimulation() calls the module’s initialization and reset
methods before the scheduled updates begin.
import numpy as np
from Basilisk.architecture import messaging
from Basilisk.moduleTemplates import cModuleTemplate
from Basilisk.utilities import SimulationBaseClass, macros
simulation = SimulationBaseClass.SimBaseClass()
time_step = macros.sec2nano(0.5) # [ns]
process = simulation.CreateNewProcess("exampleProcess")
process.addTask(simulation.CreateNewTask("exampleTask", time_step))
module = cModuleTemplate.cModuleTemplate()
module.ModelTag = "cModuleExample"
module.sampleConfigVector = [1.0, 2.0, 3.0] # [-] Preserved by reset.
simulation.AddModelToTask("exampleTask", module)
input_payload = messaging.CModuleTemplateMsgPayload()
input_payload.dataVector = [1.0, 2.0, 3.0] # [-]
input_message = messaging.CModuleTemplateMsg().write(input_payload)
module.dataInMsg.subscribeTo(input_message)
recorder = module.dataOutMsg.recorder()
simulation.AddModelToTask("exampleTask", recorder)
simulation.InitializeSimulation()
simulation.ConfigureStopTime(2 * time_step)
simulation.ExecuteSimulation()
expected = [[2.0, 2.0, 3.0], [3.0, 2.0, 3.0], [4.0, 2.0, 3.0]] # [-]
np.testing.assert_array_equal(recorder.dataVector, expected)
np.testing.assert_array_equal(recorder.times(), [0, time_step, 2 * time_step])
assert module.updateCounter == 3
To try the disconnected-input case, omit the subscribeTo() call and change expected
to [[1.0, 0.0, 0.0], [2.0, 0.0, 0.0], [3.0, 0.0, 0.0]]. The initial zero payload
written by reset is replaced by the first update before the recorder samples at time zero.
Functions
-
void SelfInit_cModuleTemplate(cModuleTemplateConfig *configData, int64_t moduleID)
This method initializes the output messages for this module.
- Parameters:
configData – The configuration data associated with this module
moduleID – The module identifier
-
void Update_cModuleTemplate(cModuleTemplateConfig *configData, uint64_t callTime, int64_t moduleID)
Add the update counter to the first component of the optional input vector.
- Parameters:
configData – The configuration data associated with the module
callTime – The clock time at which the function was called (nanoseconds)
moduleID – The module identifier
-
void Reset_cModuleTemplate(cModuleTemplateConfig *configData, uint64_t callTime, int64_t moduleID)
Reset the runtime counter and publish a zero output payload.
Note
The sampleConfigVector configuration is preserved. The inputVector scratch storage is refreshed on the next update.
- Parameters:
configData – The configuration data associated with the module
callTime – [ns] time the method is called
moduleID – The module identifier
-
struct cModuleTemplateConfig
- #include <cModuleTemplate.h>
Public module data containing runtime state, configuration, and message interfaces.
Public Members
-
double updateCounter
[-] Runtime counter; Reset clears it and Update increments it.
-
double sampleConfigVector[3]
[-] Sample configuration for logging; retained by Reset and unused by Update.
-
CModuleTemplateMsg_C dataOutMsg
sample output message
-
CModuleTemplateMsg_C dataInMsg
sample input message
-
double inputVector[3]
[-] Input scratch storage; overwritten on every Update.
-
BSKLogger *bskLogger
BSK Logging.
-
double updateCounter