How to write expression to change HW component behavior#

Exprtk library#

In various scenarios, you may want to modify the drone components behavior. To achieve that, Parrot Sphinx offers the feature of injecting mathematical expressions using the ExprTk syntax in real time. It is possible in JSON-RPC variables that generally end with Expr or Function.

Most of the keywords recognized by ExprTk are listed below:

  • Mathematical operators:

    +, -, *, /, %, ^
    
  • Functions:

    min, max, avg, sum, abs, ceil, floor, round, roundn,
    exp, log, log10, logn, root, sqrt, clamp, inrange, swap
    
  • Trigonometry:

    sin, cos, tan, acos, asin, atan, atan2, cosh, cot,
    csc, sec, sinh, tanh, d2r, r2d, d2g, g2d, hyp
    
  • Equalities, Inequalities:

    =, ==, <>, !=, <, <=, >, >=
    
  • Assignment:

    :=, +=, -=, *=, /=, %=
    
  • Boolean logic:

    and, mand, mor, nand, nor, not, or, xor, xnor
    
  • Control Structures (if-then-else, ternary conditional, switch case, return-statement)

  • Loop Structures (while loop, for loop, repeat until loop, break, continue)

  • String operations (equalities, inequalities, boolean logic, concatenation and ranges)

  • Expression local variables, vectors and strings

  • User defined variables, vectors, strings, constants and function support

Component parameters that support ExprTk syntax are recognized by the “_expr” at the end of their name. For instance, IMU’s acceleration in X can be modified by setting the value of its acceleroX_expr component parameter (see Interact with the simulation for more information on component parameters).

Special variables and functions#

To help the user write expressions for component parameters, Parrot Sphinx provides additional variables and functions in the expression evaluation context.

Current value#

By default, expressions are often set to val. val usually refers to the exact and actual value before any modification. For example, in the context of the acceleroX_expr component parameter, the val variable refers to the real acceleration in X. In the context of the gyroP_expr component parameter, the val variable refers to the real angular velocity around the X axis. So, setting an expression to val usually means the original value will remain unaffected.

Predefined variables#

All ExprTk JSON-RPC expressions can have access to a set of predefined variables. Some of them are common to all the functions, while others are specific to a given type of drone component, such as motor or aerodynamics.

Below is the list of the predefined variables common to all ExprTk expressions:

  • posX: X coordinate in world frame [m]

  • posY: Y coordinate in world frame [m]

  • posZ: Z coordinate in world frame [m]

  • speedX: linear body speeds [m/s]

  • speedY: linear body speeds [m/s]

  • speedZ: linear body speeds [m/s]

  • accX: linear body accelerations [m/s²]

  • accY: linear body accelerations [m/s²]

  • accZ: linear body accelerations [m/s²]

  • p: roll [rad]

  • q: pitch [rad]

  • r: yaw [rad]

  • phi: angular body speeds [rad/s]

  • theta: angular body speeds [rad/s]

  • psi: angular body speeds [rad/s]

  • phidot: X angular body accelerations [rad/s²]

  • thetadot: Y angular body accelerations [rad/s²]

  • psidot: Z angular body accelerations [rad/s²]

  • temperature: atmospheric pressure at the current location of the drone. [°C]

  • pressure: atmospheric pressure at the current location of the drone. [Pa]

  • atm_density_ratio: ratio between current atmospheric density over reference atmospheric density (atmospheric density at altitude 0 at 15°C)

  • time: time of the simulation since the launch of Parrot Sphinx. [s]

  • rtime: time of the simulation since the last expression edition drone-wide. [s]

Noise functions#

noise()#

The noise() function is defined as \(~\mathcal{N}(0,1)\).

By editing the expression string, it is easy to change the standard deviation (std = 10) and the mean (mean = 2) of the noise:

acceleroX_expr = val + noise() * 10 + 2

randu()#

The randu() function is defined as \(~\mathcal{U}\) (uniform distribution between 0 and 1).

This function is useful in particular to select an output function with a given probability, for example:

acceleroX_expr =  (0.001 > randu()) ? val + noise() * 0.05 : val + noise() * 0.01

randwalk()#

The randwalk() function is defined as an accumulation of noise data following \(~\mathcal{N}(0,1)\) over time (random walk).

Example:

pressure_expr = 1.756*noise()+0.05*randwalk()

Accumulated data is reset to zero each time that a parameter held by the transformer is changed.

markov_noise()#

The markov_noise(k, std) function is defined as an accumulation of noise data which depends on the previously computed value. Mathematically it corresponds to:

\[mn(k, std) = ~\mathcal{N}(0,std) + k * acc\]

where acc is what was accumulated at the previous iteration (starts at 0).

It has two parameters:

  • k (between 0.0 and 1.0) which defines how much of the previous value is kept.

  • std is the standard deviation of the noise range.

Example:

markov_noise(0.5, 1.0) # 50% of the accumulator value is added to a gaussian of std 1.0
markov_noise(1.0, 0.0) # Same as noise()
markov_noise(1.0, 1.0) # Same as randwalk()

Accumulated data is reset to zero each time that a parameter held by the transformer is changed.

Area functions#

outside_area()#

The outside_area('area_name') function returns 1.0 if the drone is outside the area named area_name and any areas that contain the tag area_name, 0.0 otherwise.

This function can be used, for example, to restrict the number of satellites in view for the GPS device:

num_sv_expr = 12 * outside_area('indoor_area')

inside_area()#

The inside_area('area_name') function returns 1.0 if the drone is inside the area named area_name and any areas that contain the tag area_name, 0.0 otherwise.

Modify the output of sensors#

Most of the expressions affecting the output of sensors are set to val to return a perfect output. For some sensors, like the barometer, the firmware considers the sensor to be defective if it receives perfect output. In such cases, a minimal noise is added by default:

pressure_expr = val + noise() * 0.01

The list of available expressions for each sensor can be found on their respective reference page.

You can modify the expressions altering the output of sensors with the sphinx-cli param command.

Example 1: The following example shows how to modify the Y-axis component of the accelerometer output by adding a sinus to it:

$ sphinx-cli param imu/icm40609 acceleroY_expr "val + sin(time) * 10"

Example 2: The following example shows how to modify the barometer pressure output by adding noise and a bias error of 12 Pa to it:

$ sphinx-cli param barometer/lps22hb pressure_expr "val + noise() * 0.01 + 12"

Example 3: The following example shows how to modify the barometer pressure output by adding noise and a bias error depending on the altitude to it:

$ sphinx-cli param barometer/lps22hb pressure_expr "val + noise() * 0.01 + posZ"

You can also define local variables to write more complex expressions in a clear way. For instance, you can define constants, or normalize variables. Here is the syntax to use (don’t forget the semicolon).

var name := value;

Warning

Do not try to override the definition of predefined variables.