OpenTx - Key Concepts

Mike Shellim 25 July 2014
Last updated: 29 July 2019 - expanded section on Inputs

Para nuestros amigos hispano-hablantes: traducción al español en formato PDF. Muchas gracias a Jorge Brun.


OpenTx is a uniquely flexible system. However if you've come from a brand like Futaba or Spektrum then you'll find the way of working a little unfamiliar. My aim with this article is to shed some light on how it works, and to enable you to design your own setups with confidence. I'll cover the following topics:

Examples will be illustrated either with screenshots or as text boxes, as appropriate.


OpenTx has just seven programming menus, and each is completely generic. This concept of generic simplicity extends to the mixers. Rather like Lego, a small number of simple elements can be used to build powerful solutions.

OpenTx: the processing loop

The core of OpenTx (as with any RC system) is the processing loop. This is a sequence of operations repeated several times a second - fast enough to provide a smooth response.

With each cycle, the position of all the controls are read, mixing is applied, and the commands for each channel are calculated. At the end of the cycle, the channel commands are passed to the RF module for transmission.


The three key processing steps are marked in blue. Each has an associated menu ('INPUTS', 'MIXERS' and 'OUTPUTS'). The INPUTS and MIXERS menus are where you design the control logic. The OUTPUTS menu is for calibrating the servos (ensuring accurate centres and equal movement etc.). A change at one level propagates to levels lower down.

The starting point: Sources

OpenTx is a computer program, and like all programs it needs data to work with. In this case the data comes from your transmitter's sticks, trims, knobs and switches. A generic term for these is sources. Each source has a unique identifier, for example,

The naming of sources is broadly similar between different FrSky transmitters, but there are some differences, e.g. knobs are generally S1 and S2, except on the X9E where they are F1 and F2.

At the start of the processing cycle, OpenTx reads each source, and assigns a value between -100 and 100 according to the position. Zero corresponds to centre; for sticks, left/down is negative; right/up positive. For switches, up is negative, down is positive.

So for example,

Source values can be monitored in real time in the ANALOG INPUTS menu.

Note: channels, Lua scripts and telemetry can also be used as sources, however they will not be considered further in this article.


OpenTx can command up to 32 freely assignable channels. The lowest numbered channels will be used for devices such as servos, ESCs, flight controllers etc. A channel which is not assigned to a device may be left unused, or employed as a 'high channel'. Management of channels is split between the OUTPUTS and MIXERS menu.

The OUTPUTS menu

The OUTPUTS menu is where you give a channel a memorable name, and set the travel limits and centres.

Below is an example for a simple RES sailplane. The first three channels have been named 'Rudder', 'Elev' and 'Spoilr'. The travels and centers are at their default values.


Note that it doesn't say how each channel is driven - or even that it's driven at all. For that, we need to define some mixers...


So far we've looked at the roles of sources and channels in isolation. In order to do anything useful, we need to link them; this is the job of the mixer.

Mixers act as the 'wiring' between sources and channels; they define which channels should respond to stick movements, also how the channels should respond.

Unlike other RC systems, a mixer in OpenTx is a very simple construct:

A typical setup will involve anything from a few to dozens of mixers.

The MIXERS menu

The MIXERS menu displays a list of all the channels. Each non-blank line represents a mixer. In the screenshot below, there's a single mix, from the aileron stick to channel 1:

Read this as "Channel 1 is affected by the aileron stick, with 100% effect".

The first column is the channel number in the format CHnn. The second column is the mixer weight expressed as a percentage. 100% means maximum effect, 0% means zero effect. A negative weight reverses the effect. The third colum is the source of the mix (stick, knob etc).

Three mixing scenarios

Let's now look at three generic mixing scenarios. These will form the building blocks of your setup.

Scenario 1: One source -> one channel

This is the simplest scenario. We've already looked at an example where the aileron stick drives CH1. 100% of the aileron command is passed to the output:

Scenario 2: One source -> multiple channels

A single source can drive more than one channel. In the example below, the aileron stick drives both CH1 and CH5. This is a popular configuration for dual ailerons:

This configuration emulates a Y-lead but is more flexible since each channel can be individually adjusted for direction, travel and centring via the OUTPUTS menu.

Scenario 3: Multiple sources -> one channel

A channel can also be driven by multiple sources. A common example of this is a V-tail channel - the surface is controlled simultaneously by Rudder and Elevator sticks, as in the following example:

Note the '+' sign against the Ele line, this indicates that the rudder and elevator inputs are added to produce the output. When using the add operator, the order of the mixers doesn't matter. Other operators like multiply and replace can also be used, and the order for these is important (we'll look at those later).

Designing your mixers

It's one thing to know how mixers work, but quite another to understand how to combine them in order to build a complete working system. So here's a simple 6-step design method which I use and recommend. It can be applied to applications of any complexity. The basic idea is to define your sources, outputs and mixes in that order.

To illustrate the technique we'll use the example of a 2-channel flying wing. While trivially simple, it shows the elegance and power of OpenTx's mixing model.

Step 1. List the sources

The first step is to list the sources controlling the model. The list will normally include Rud, Ail, Ele as well as sliders for camber control, tow release etc - anything which requires a servo or ESC to respond.

Don't include flight mode switches or rate switches. Also, note that trim values are included with their parent control by default.

Our flying wing example uses just two controls, the aileron and elevator sticks, so write these down:

Step 2. List the servo channels

In this step, we assign the channels. This can be done directly in the OUTPUTS menu.

Our flying wing uses just two servos, so we'll assign two channels named 'RtEvon' and 'LtEvon':


Step 3. Identify interactions

In this key step, we identify the interactions between the sources (sticks) and channels. Write in the form 'source -> channel'

For our flying wing, the Ail source and affects channels CH1 and CH2. So:

Similarly, the interactions for the second source (Ele) are:

So for our flying wing there will be four mixes in total. In this step we're not interested in how the channels are affected, just the fact that the interactions exist.

Step 4: Convert interactions into mixer definitions

Next, swap the left and right sides of each interaction so that they read as "channel is affected by source".

Step 5: Reorder interactions by channel number

Now, re-order the mixer definitions so that they're grouped by channel.

Step 6: Enter definitions into the MIXER menu

Finally, enter the interactions as mixer definitions:

The '+=' means on each line shows that the mixes are additive.

Once you've done this a few times, you'll be able to do it in your head. But I still recommend using Companion for your first experiments, and for complex setups - mistakes are much easier to debug on a big screen!

Mixer weights

In this section, we'll see how to use the mixer weight parameter. Weights are specified as percentages. A value of zero means no movement, 100 means that the mixer source value is 'passed thru'

We'll illustrate this with our flying wing example.

As this is a flying wing, roll commands must generate more movement. We therefore set a higher weight for the Ail mixes than for Ele. Use arbitrary values to begin with, by way of illustration.

Note that the Ail weight is negative for one of the mixes and positive in the other. This is because ailerons move in opposite directions.

Our flying wing setup will now work! But it's not really finished...

Using Inputs

Our flying wing setup works, but it has a shortcoming: in order to adjust a control rate, we have to alter the mixer weight in two places - that's double the work, and double the chance of error:

We can avoid duplicates by using Inputs (introduced in OpenTx v. 2.0).

The INPUTS menu

An input is the same as a regular source, except it has weight and expo included. Using inputs makes it easier to adjust rates and expo, as it can be done in one place.

Using our flying wing example, we'll define a couple of inputs for the Ail and Ele controls.

  1. Open the INPUTS menu
  2. Name the first input as '[I]Ail' and set the source to Ail.
  3. Name the second input as '[I]Ele' and set the source to Ele.
  4. Finally, set weight and expo to the required values

This is how it looks in the menu:


The two inputs behave exactly as the "raw" ail and ele sources, but with reduced weight and 10% expo.

We can now use them as our mixer sources (instead of the raw sticks). Since the rates are now specified in our new inputs, we should reset the mixer weights to +/-100%. This is good practice, as it localises the rate adjustment to just the Inputs menu:


The OUTPUTS menu remains unchanged (for now):


More about Inputs

In this section, we'll look into Inputs in more detail.

OpenTx provides a maximum of 32 inputs. Each input has a label of the form [In], where n is an internal index (it's not related to channel numbers or mixers).

In order to do anything useful, an input must have:

System-created inputs

When you create a new model, OpenTx automatically sets up one input for each of the main controls: [I1]Ail, [I2]Ele, [I3]Thr, [I4]Rud with default weights of 100%. It also creates mixers for these inputs in channels 1-4. Of course, you're can edit - or delete - these mixers and inputs.

Inputs with multiple lines - example rate switch

Inputs may include more than one detail line, each dedicated to specific switch and/or flight mode. You can use this to build a rate switch.

Here's an example of a rate switch for the aileron function, using switch SB:


Ail Weight(+33%) Switch(SB↑)

Ail Weight(+66%) Switch(SB-)

Ail Weight(+100%) Switch(SB↓)

Let's see how this works:

OpenTx starts at the top line (SB↑). It checks the actual position of SB. If there's a match, the line becomes active. If there's no match, it advances to the next line and repeats the test. And so on, until a match is found or the list is exhausted.

If OpenTx reaches the end of the list without finding a match, the input will not function at all! You as the programmer are responsible for making sure this does not happen!

In the previous example, each of the possible switch positions have a line, so SB will function as intended.

Defensive programming: using a 'catchall' line.

Now let's now introduce an error to the previous example:


Ail Weight(+33%) Switch(SB↑)

Ail Weight(+66%) Switch(SB-)

Ail Weight(+100%) Switch(SA↓) -- SA instead of SB!!!

The intention is for SB to be the rate switch, but I've mistakely typed 'SA' instead of SB in the last line. The effect of this is quite subtle. If SA is down, then moving SB downwards will select high rate as intended. However if SA is up and high rate is selected, there will be no matching line - the aileron control will freeze, possibly causing a crash!!

To mitigate the effects of such errors, the last input should be a 'catchall', in other words with the switch field empty, and all flightmode checked. That way a match is guaranteed even if there are errors in the previous lines, so the aileron will continue to function:


Ail Weight(+33%) Switch(SB↑)

Ail Weight(+66%) Switch(SB-)

Ail Weight(+100%) Switch(SA↓) -- SA instead of SB!!!

Ail Weight(+66%) -- 'catchall' as last line

Adding a catchall line is good defensive programming.

A catchall line can also function as a default setting to simpify the input list. So in the example below, SB-up corresponds to low rate, all other positions fall through to the catchall line for a 50% rate.


Ail Weight(+33%) Switch(SB↑)

Ail Weight(+50%)

Choosing between raw sources and inputs as mixer sources

Inputs are optional, and it doesn't always make sense to use them.

How mixer and channel outputs are calculated

In this section we'll look in detail at how OpenTx converts stick movements into position commands. An understanding will be come in useful when debugging your setup.

Mixer output values

OpenTx performs two stages of calculation, first at the level of the mixers, and then for the channel as a whole.

For each mix, OpenTx calculates the mixer output according the weight (and other parameters we'll look at later). Taking our flying wing example, at any moment the mixer outputs are as follows:

Channel 1

mix_1 = Ail_stick_value x 90%

mix_2 = Ele_stick_value x 30%


Channel 2

mix_1 = Ail_stick_value x -90%

mix_2 = Ele_stick_value x 30%

Channel values

OpenTx then aggregates the mixer outputs for each channel. The result is the channel output value. This represents the commanded position. Using our flying wing:

ch1 = (Ail_stick_val x 90%)+(Ele_stick_val x 30%)
ch2 = (Ail_stick_val x -90%)+(Ele_stick_val x 30%)

Here are the numbers for our flying wing example:

Ail stick Ele stick CH1 CH2
(centre) 0  (centre) 0 0 0
(full  right) 100% (centre) 0 90+0=90 -90+0=-90
(full left) -100%  (centre) 0  -90+0=-90 90+0=90
(centre) 0 (full forward) 100% 0+30=30 0+30=30
(half right) 50% (half forward) 50%  45+15=60 -45+15=-30
(full  right) 100% (full forward) 100% 90+30=120 -90+30=-60

The last line shows the effect of "stick in the corner" - note the commanded position for Channel 1 is 120. In fact, OpenTx clips the channel values to +/- 100 in the OUTPUTS section - this ensures that servo travel is confined within safe bounds. More on that later.

More about mixers

OpenTx offers a number of mechanisms for conditioning the output of a mix. We've already looked at weight. We'll now investigate offset, expo, diff, functions and curves.

Mixer offset

The offset parameter is used to shift the mixer output up or down. Using offset in conjunction with weight, you can create mixes whose output varies between a defined range. This is useful for creating volume controls, and also for compensation mixes.

When calculating the output of a mixer, offset is applied after weight:

Mixer output = (Source * weight) + Offset

Offset example 1: custom volume control

Suppose you want to create volume control (S1), with output varying from -50 to +90 as S1 is rotated. We can do this as follows (remembering that the value of S1 varies from -100 to +100):


Src = 'S1', wt=70%, offset=20

Offset example 2: motor-elevator compensation. Offsets are commonly used for crow and motor mixes, in particular 'compensation' mixes. For these mixes, the output must be zero at the idle end of stick travel.

The example below shows a typical motor-elevator mix. The first line is the standard elevator mix, the second line is for motor compensation.


CH2 (elevator)

Src=Ele, wt=100%, offset = 0

Src=Thr, wt=20%, offset=20

Note how weight and offset are the same value - this ensures that the output is zero when the throttle stick is at back/idle (-100). At full throttle (+100) the output will be 2 * weight = 40. To reverse the stick, change the sign of weight.

Note: offsets should be used sparingly! Never use them to make ad-hoc adjustments to your servo centres or end points - use the OUTPUTS menu for that.

Diff, expo, functions and curves

In addition to weight and offset, OpenTx provides one additional option from the following:

The 'Curve' option provides the most granularity - it can implement all the other options, but requires the most data entry.

Using the 'diff' option

Sailplanes often employ aileron differential. The purpose is to reduce the travel of the downgoing aileron. First, here's the obvious - but incorrect - way:



Src=Ail, wt=90%, expo=10, diff=20



CH1 (right elevon)

Src = [I1], wt=100%


CH2 (left elevon)

Src = [I1], wt=-100%

The problem: diff is applied to the input, so the aileron stick will have a higher rate on one side than the other. This is not what we want! Instead, diff must be applied separately to each aileron channel:



Src=Ail, wt=90%, expo=10, diff=0



CH1 (right elevon)

Src = [I1], wt=100%, diff=20%


CH2 (left elevon)

Src = [I1], wt=-100%, diff=20%

To summarise: specify diff separately for each aileron channel. Do not specify diff at the Input level.

TIP: Use a GVAR to supply the diff value. That way, you can set diff for both channels with a single adjustments.

Including/excluding trims

By default, trim values are included in sources. You can exclude trims on a per-mixer basis by unchecking "Include Trim" in the mixer dialog.

For our flying wing example, aileron and elevator trims must always be active, so we'll use the default settings.

Default mixer settings

When you create a new mix, the initial settings are weight=100% and offset=0, diff/expo=0 and no curve. The source value is therefore passed through unchanged.

Order of processing

When calculating the output of a mix, OpenTx first applies the trim value. Then it applies the function (diff, function, curve, expo), followed by weight, and finally adds the offset. Order may be important when combining operators especially where offsets are involved.

The OUTPUTS menu

In the final step of the processing loop, OpenTx (a) clips the channel values to +/- 100%, and (b) applies a scaling and offset defined the settings in the OUTPUTS menu. Together, this contrains the output to within safe bounds, while allowing adjustment of servo limits and centres.



We've seen how the channel output is calculated as the sum of all these the mixer outputs:

CHxOutput = SUM (CHxMixerOutput1, CHxMixerOutput2, ...)

If several mixers are active, then the channel value could exceed the safe limits of the servo. To avoid this, channel values are clipped in the OUTPUTS stage so they lie in the range -100 to +100. Clipping manifests itself as deadband at the transmitter control.

Scaling and offset

Next, the channel commands are scaled and offset. This is where you map channel values to actual servo actual positions.

First, an optional curve is applied (specified in the Curve field). Curves may be between 2 and 17 points, and provide fine grained control over the channel response.

Next, the command is scaled according to MIN, MAX and SUBTRIM. Think of these as a three point curve defining the end points and centre.


Where to adjust weights

The three processing layers (Inputs, Mixers, and Outputs) apply a weight to their inputs. As a source value propagates through these layers, each rate is applied to the result of the previous layer. The the final servo command will be the product of at least three rates:

OutputValue = SourceValue x Rateinput x Ratemix x Rateoutput

Clearly there is an infinite combination of rates which will produce the same movement at the servo. So where should you set them? This is the procedure I recommend:

  1. Initialise all weights in MIXERS and INPUTS to 100%.
  2. Calibrate the servo centres and end points. To do this, go to the OUTPUTS menu. Move each control to one or other end stop and adjust MIN/MAX to set the limits of travel. Then adjust SUBTRIM for correct centres.
  3. The control surface movements after step (2) will be excessive. To achieve the movements required for flight, adjust the weights in the INPUTS menu.
  4. Any remaining mixer interactions can be adjusted via weights in the MIXERS menu.

More advanced stuff

Mixer operators

So far, we've assumed that mixer outputs are always added together. In fact OpenTx is a good deal more flexible - it also permits multiplication and replace operations. This is very useful. For example, multiplication is key to implementing in-flight adjusters, and 'replace' can be used to implement throttle safety switches.

The key is the mixer's multiplex parameter. This defines how the mixer's value should update the channel value. The options are 'ADD' (the default), 'REPL' and 'MULT'.

When calculating a channel value, OpenTx initially assigns a value of zero. It then steps through all the mixers in the channel, starting from the top. Processing of each mix depends on the multiplex parameter:


The following examples illustrate the effect of the various multiplex options. Note the importance of mixer order when using 'REPL' and 'MULT'.

Src = I1, op=ADD

Src = I2, op=ADD

output = I1 + I2

Src = I1, op=ADD

Src = I2, op=ADD

Src = I3, op=MULT

output = (I1 + I2) * I3

Src = I1, op=ADD

Src = I2, op=MULT

Src = I3, op=ADD

output = (I1 * I2) + I3

Src = I1, op=ADD

Src = I2, op=MULT (disabled)

Src = I3, op=ADD

output = I1 + I3

Src = I1, op=ADD

Src = I2, op=REPL

Src = I3, op=ADD

output = I2 + I3

Src = I1, op=ADD

Src = I2, op=REPL

Src = I3, op=MULT

output = I2 * I3

Src = I1, op=ADD (disabled)

output = 0

The 'MAX' source

MAX is a special source which doesn't correspond to a physical control. Instead, MAX supplies a fixed value of +100. In conjunction with weight, it can be used to simulate the effect of a fixed stick position.

Src = MAX, wt =100 -- output = 100%

Src = MAX, wt=50 -- output = 50%

Src = MAX, wt=-100 -- output = -100%

Here's a simple example, showing a crude motor arming system. The motor is armed when SA is down.


CH7 (motor)

Src = Thr, wt=100%,

Src = MAX, wt=-100%, switch=!SA_down, multiplex = REPL

F3X sailplane mixer scheme

If you're familiar with F3X sailplanes, you may wish to look at interactions and mixes for F3X sailplanes. Such a scheme will normally be optimised by means of Inputs (described later in this article), GVARs and cascading mixers.


LapinFou has produced some useful data flow diagrams which describe the internal workings of OpenTx (Note: at the time of writing, there are one or two errors in the order of processing of curves).