Aircraft example¶
Here you can see how to use an HLA-based definition to implement a simple aircraft simulation using
the update() method.
Interface and Implementation¶
In the aircraft.stl file you can see how we inherit from rpr.Aircraft, and in the implementation
dummy_aircraft.cpp you can see a (dummy) implementation of the update function.
// === dummy_aircraft_impl.cpp =========================================================================================
// Sen Infrastructure
// Released under the Apache License v2.0 (SPDX-License-Identifier Apache-2.0).
// See the LICENSE.txt file for more information.
// © Airbus SAS, Airbus Helicopters, and Airbus Defence and Space SAU/GmbH/SAS.
// =====================================================================================================================
// generated code
#include "rpr/rpr-base_v2.0.xml.h"
#include "stl/dummy_aircraft.stl.h"
// sen
#include "sen/core/base/compiler_macros.h"
#include "sen/core/meta/class_type.h"
#include "sen/kernel/component_api.h"
#include "sen/util/dr/dead_reckoner.h"
#include "sen/util/dr/settable_dead_reckoner.h"
// std
#include <cmath>
#include <memory>
namespace aircrafts
{
// An aircraft that updates its position.
class DummyAircraftImpl: public DummyAircraftBase<>
{
SEN_NOCOPY_NOMOVE(DummyAircraftImpl)
// type alias
using SettableDr = sen::util::SettableDeadReckoner<rpr::BaseEntityBase<>>;
using DeadReckoner = sen::util::DeadReckoner<rpr::BaseEntityBase<>>;
public:
using DummyAircraftBase<>::DummyAircraftBase;
~DummyAircraftImpl() override = default;
public:
void registered(sen::kernel::RegistrationApi& /*api*/) override
{
// the DeadReckoner is used to update the world location of the aircraft given the configured speed. This is not
// the regular use of the DeadReckoner but it comes in handy for the example.
deadReckoner_ = std::make_unique<DeadReckoner>(*this);
// the SettablaDeadReckoner is used to update the Spatial field of the aircraft
settableDeadReckoner_ = std::make_unique<SettableDr>(*this);
}
void update(sen::kernel::RunApi& api) override
{
// move the entity using the dead reckoner with the specified speed
auto situation = deadReckoner_->geodeticSituation(api.getTime());
// initialize the situation of the entity in the first iteration
if (!init_)
{
situation.worldLocation = {40.0, 0.0, 10000.0};
init_ = true;
}
// update the speed (can be changed while the model is running)
situation.velocityVector = {getSpeed(), 0, 0};
// update the spatial using the settable dead reckoner
settableDeadReckoner_->setSpatial(situation);
}
private:
bool init_ = false;
std::unique_ptr<DeadReckoner> deadReckoner_;
std::unique_ptr<SettableDr> settableDeadReckoner_;
};
SEN_EXPORT_CLASS(DummyAircraftImpl)
} // namespace aircrafts
How to run it¶
Let's define what we want to run in our Sen kernel.
# $schema: ../base/schema.json
include:
- ../base/shell.yaml
build:
- name: myComponent
freqHz: 30
imports: [aircrafts]
group: 3
objects:
- class: aircrafts.DummyAircraftImpl
name: myAircraft
bus: my.tutorial
speed: 250
entityType: &theType
entityKind: 1
domain: 2
countryCode: 198
category: 1
subcategory: 3
specific: 0
extra: 0
alternateEntityType: *theType
entityIdentifier:
entityNumber: 1
federateIdentifier:
siteID: 1
applicationID: 1
This will open a shell and tell Sen to instantiate one aircraft in the my.tutorial bus.
To run it, let's call sen run:
You should be able to repeatedly call my.tutorial.myAircraft.getSpatial and see the evolution of
the position.
Using the explorer¶
You can also load the explorer to have an easier time following the updates.
Using virtualized time¶
Let's now start the kernel in virtualized time mode by changing our config file.
# $schema: ../base/schema.json
include:
- 1_aircraft.yaml
# In this example we start the kernel with the virtualized time.
# Here the time will not advance until we explicitly request it.
# You will find that the kernel will be publishing an object called
# 'clock' in the 'my.tutorial' bus, that you can use to control the
# virtual time and see how components advance accordingly.
kernel:
runMode: virtualTime
clockMaster: true
clockBus: my.tutorial
We can run it with the following command:
Now, if you execute my.tutorial.myAircraft.getSpatial you will see that there are no updates.
Let's now advance one cycle by using the clock API.
You can see how the component got triggered.
If you want to advance the time more, say 60 seconds:
This should run relatively fast, as we are not performing expensive computations.