SpeedControl demo project
To get hands on the CppModel environment let us start with a simple speed control function written in C. For the purpose of presentation function only makes the following calculations:
- calculating the percentage value of left wheel command given the percentage speed and direction angle
- calculating the percentage value of right wheel command given the percentage speed and direction angle
For simplicity the direction angle is given in degrees. Input values are in range speed [0:100] % and direction [-90:90] deg. Input validity check is skipped and output values are directly assigned to minimize the code length. Under given assumptions the C function can be written as follows:
speedControl.h
#include <stdint.h>
typedef struct SpeedControlContext_s
{
int8_t directionAngleDeg;
int8_t controlCommandPercent;
int8_t leftWheelPercent;
int8_t rightWheelPercent;
} SpeedControlContext_ts;
void speedControlCyclic(SpeedControlContext_ts *const ctx);
speedControl.c
#include <math.h>
#include "speedControl.h"
void speedControlCyclic(SpeedControlContext_ts *const ctx)
{
ctx->leftWheelPercent = (ctx->directionAngleDeg <= 0)
? ctx->controlCommandPercent
: cos(((float)ctx->directionAngleDeg * M_PI) / 180) * ctx->controlCommandPercent;
ctx->rightWheelPercent = (ctx->directionAngleDeg >= 0)
? ctx->controlCommandPercent
: cos(((float)ctx->directionAngleDeg * M_PI) / 180) * ctx->controlCommandPercent;
}
This could be the code which will be used later on in the embedded system.
Before you start with simulation you might want to install the CppModel client side libraries. You can obtain them from Downloads page.
To make it possible to present graphical results from the above C function the function could be made part of a simulation with proper execution time and cyclic call events. In CppModel this is a responsibility of the Simulation class. The simulation implementation for this function would look as follows:
SimulateSpeedControl.h
#pragma once
#include <cppmodel/Simulation.h>
class SimulateSpeedControl : public CppModelBase::Simulation
{
public:
SimulateSpeedControl(std::string apiKey);
void RunCyclic(double simulationTime);
};
Simulation class has a RunCyclic() method which is being called every simulation step and it will provide the current execution time in seconds.
SimulateSpeedControl.cpp
#include "SimulateSpeedControl.h"
extern "C"
{
#include "speedControl.h"
}
SimulateSpeedControl::SimulateSpeedControl(std::string apiKey)
: CppModelBase::Simulation(apiKey)
{
name = "SpeedControl";
time = 20; // Seconds
stepSize = 0.02; // 20 ms
}
void SimulateSpeedControl::RunCyclic(double simulationTime)
{
SpeedControlContext_ts speedControlCtx;
speedControlCtx.directionAngleDeg = inputs["Direction"];
speedControlCtx.controlCommandPercent = inputs["Speed"];
speedControlCyclic(&speedControlCtx);
outputs["LeftWheel %"] = speedControlCtx.leftWheelPercent;
outputs["RightWheel %"] = speedControlCtx.rightWheelPercent;
}
The implementation of the custom simulation class needs to define several parameters in order to provide proper execution environment and presentation later on. The property apiKey is the link between this program and visual workspace environment identifying you as the owner of the key. As you may have several models to distinguish between them in the visual workspace it is necessary to set the name property. Properties time and stepSize control the execution. The simulation will be running for the selected amount of seconds and RunCyclic method will be called every stepSize amount of time.
Once these properties are set we can proceed to execution of the simulation. As mentioned before the RunCyclic method is going to be called for every simulation step, therefore that is a good place to place the call to underlying function. In this case we would like to set some predefined values for function inputs, call the function and visualize its resulting data. In CppModel this is achieved by using inputs and outputs properties of the Simulation class. The inputs property reads workspace variables identified by name (in this case "Direction" and "Speed") and provides them to Simulation class. Whereas outputs property submits the results of the execution to the visual workspace, again identified by name.
With this implementation the simulation is ready to be executed and the last thing left is to actually run it. This can be done simply by calling its Simulate() method.
#include "SimulateSpeedControl.h"
int main(void)
{
SimulateSpeedControl sim(CPPMODEL_API_KEY);
sim.Simulate();
return 0;
}
Finally to compile the project make sure to link with the CppModelBase library. Here is a CMake configurarton that controls example compilation process. If you have not yet obtained your API key and installed the CppModel libraries make sure to do so before compilation.
project(SpeedControl)
# Add your own API key here
add_compile_definitions(CPPMODEL_API_KEY="Your API key.")
add_executable(SimulateSpeedControl speedControl.c SimulateSpeedControl.cpp execute.cpp)
target_link_libraries(SimulateSpeedControl CppModelBase)
Compiling and running the file will produce output that looks like this:
UI: http://model.cppmodel.com?apiKey=Your API key&simName=SpeedControl
This link will get you directly in the current simulation workspace, where the results of the latest execution will be presented.