A new approach to ArduPlane Mixer Scripting

ArduPlane mixing leaves a lot to be desired. One major issue is the RC_Channel class, which is quite difficult to fathom. I hope to work on that at some stage, but first am looking at how to script a mixer. I have looked both at PX4 and at OpenTX mixers, but have decided on a more programming language approach.

The language is simple with a strong grammer and uses strong typing and type deduction. Simplest mixer:

https://github.com/kwikius/mixer_lang/blob/master/EasyStar.mix

A more complex example is as shown in this glider mixer, which is designed for a glider that has a V-tail variable camber and crow flaps.

https://github.com/kwikius/mixer_lang/blob/master/glider.mix

The implementation builds an expression tree and also does constant folding. Strong typing is good for speed, since errors are checked as the expression tree is built. Many complex constant expressions are evaluated into one constant value as the tree is built, so reducing the size of the tree. The memory used for symbol names is also recoverable once the tree is built. Since the expression is built close to startup only, this works out quite well.

Currently the system works only as a PC application with hardwired inputs and some command line diagnostic…

https://github.com/kwikius/mixer_lang

…but it is evolving slowly and I am looking to get some more exciting inputs soon.

Having recently discovered that the Taranis is simple to hook up as a PC joystick. For now I wrote a simple app to just display the Taranis stick inputs.

https://github.com/kwikius/Taranis_linux_joystick

The next task is to hook the mixer language up to the joystick to provide some runtime action of the inputs :).

1 Like

Now The mixer is updated so you can use your Taranis for joystick input. For best results create a model that provides Ideal outputs for pitch yaw roll throttle, since now the mixing is moved to the plane. (For best results make sure your Taranis has been calibrated using the routine on the Tx)

@skyscraper, I think it is a great idea to add a general purpose mixer to ardupilot. What I’d really like to see though is a binary format to define the mixer. So we’d have a text format that a GCS could have an editor for and a binary format that is transmitted to the aircraft and interpreted in flight.
It has been a real pain having the text mixer format in PX4IO so I’d like to get away from text formats inside the autopilot. I would like a way to be able to dump the mixer to a file from within ardupilot, but I think the protocol to upload a new mixer should be binary.
I also think we should have named mixers, so you can have a MAVLink command to select a mixer by name, or to download, upload etc.

@tridge
I would be interested to know what problems you had with the PX4 mixer.

BTW The mixer I am proposing is capable of handling much more complexity than in the example above. I put that there as a minimal example.
Here for example is a mixer for a glider with crow flaps:

https://github.com/kwikius/mixer_lang/blob/master/glider.mix

Regarding modifying the mixer during flight

During execution the mixer can access Ardupilot Parameters which may change at runtime, so for example, if you want to use the KFF_RDDRMIX parameter http://ardupilot.org/plane/docs/parameters.html#kff-rddrmix-rudder-mix

#–oversimplified example--------
output[rudder] = input{Yaw} + input{Roll} * input{KFF_RDDRMIX};
#-------------------------------
Now if you upload a new value for KFF_RDDRMIX from your GCS then that new value for KFF_RDDRMIX will be used in the next run through the mixer.

This idea could be extended so that you have some specific variables defined in the mixer that you can update during execution:
#-------------------------------------------------------------------
# define and init an externally modifiable variable. The type (float here) determined from type of initialiser
variable{AileronGain} = 0.2;
#-------------------------------------------------------------------
You could then send commands from your GCS to update the variable during flight.

My point is that as an alternative to changing the whole mixer, you can modify variables within the current mixer via the GCS. This doesnt rule out changing the entire mixer either of course

The mixer is actually an expression tree and the mixer language uses a context free grammar. You could have a binary representing the tree and symbol table I guess.
The rationale for an expression tree is that it is strongly typed (types are determined once) and fast to execute.

several problems. One is the string functions in px4io. We’ve had a few nasty bugs with the NuttX string functions causing crashes as it parses the mixer text. It also uses a lot of stack and ram.
The most recent problem is the way it transfers the mixer text to PX4IO. There is no robust validation that the mixer got through OK. You can (rarely) get situations where only some elements of the mixer get through, so you don’t have all channels. The code is written with no verification, and the text nature of it makes good verification harder than it should be.

OK In answer to the issue re text v binary. In my offering I would argue that I am describing the mixer using a context free grammar which is neutral about whether it is expressed in binary or text. In the text version I first run the text through a lexer

https://github.com/kwikius/mixer_lang/blob/master/lexer.cpp

The lexer returns tokens which are then checked to conform to a grammar (A binary version can ignore that step)

https://github.com/kwikius/mixer_lang/blob/master/bison.y

You can use the same grammar on binary input, so from where I am with it, it wouldn’t be too difficult to create a binary file using this grammar , which could be parsed on the autopilot.
The obvious thing against a binary file format is that like machine code, most cant understand it, which is why I think that the master definition of any mixer should be text ( as in any programming language, which this basically is well a DSL https://en.wikipedia.org/wiki/Domain-specific_language). As to why not use Lua or Python? Size and speed. Both languages are pretty big, relatively and look up types dynamically AFAIR so have pretty poor performance. The language used here is small but is strongly typed, stronger than c and is actually a compiled language, being compiled into an expression tree. There is no implicit conversion from float to int to boolean, no math except on same types etc. This makes the language small. (I will probably have to add explicit casts though)

At the semantic level It would then be a question of checking limits to avoid integers rolling over etc. I cater for divide by zero by saturating at ± max
https://github.com/kwikius/mixer_lang/blob/master/mixer.cpp#L138
So it would be a question of identifying any holes, but I believe being a small language there are only a few potential holes.

So I believe the above offering can cater for binary or text, since it is expressed in terms of a grammar . Once the binary or text input gets into the parser the same tree will be emitted and the same semantics will apply.