Better mixers for Arduplane, PX4, mavlink etc

I have a challenge requiring some better mixer options. I need around 55 mixers for complete aileron, brake, flap, elevator and rudder movements. Each mixer can be up to 5 points which is 10 parameters each, a total of 550 parameters

Adding this to the parameters list is the wrong way to do it, even if there was space for it. As I understand it APM doesn’t have the resources to do more so this activity is for PX4 only.
Trimming of individual mixers is essential for reasonable ease of configuration and field trimming.

I think I may have just argued that this is a PX4 problem and not an ardupilot problem. If anyone knows of anyone already working on this it would be good to know.


APM 2.x HW had limited resources. The Parameter storage area is the same size for PX4 flight stack and ArduPilot flight stack on Pixhawk HW

Not sure what you are attempting to do, but it looks more like manual control setup for a TX idea than a flight controller.

@billb, Yes that is about right. Since the transmitter controls can be different things depending on autopilot mode then you can’t send mixed output from it. For example, an aileron has roll, pitch, flap and brake mixed into it. If the transmitter does the mixing then how do you untangle the mix to use it as commands (eg. climb rate, airspeed, band angle)?

So, all mixers must be on the aircraft if the aircraft has a flight controller.

I think I can do this by:

  1. Extend the PX4 mixer language
  2. Mavlink protocol to read the mixers and modify individual settings
  3. Python script to generate a default mixer configuration for Ardupilot
  4. A nice GUI for users to interface with

I have done this before for UDB. It was clunky so I was the only user. If I am to have any chance of moving to pixhawk hardware then I need to do this right.

Revival of this topic for 2017

@WickedShell @OXINARF @MagicRuB
The live mixer tuning discussion lead to reworking of the mixers themselves. I brought that topic out of that specific pull request to give it more visibility.
I understand tridge had some ideas on this topic. Please include him if you think it necessary.

Live mixer tuning - Pull request

There is an active google document collecting requirements and proposals. I will assign write access if requested.
MAVlink mixers description document

There is a document describing the live mixer tuning. This may merge with the above document
MAVlink mixer tuning

Just an idea, what if Ardupilot had a stick calibration learning feature. That way you would still create all the complex mixes in the RC radio. Then activate RC_STICK_LEARN. Move all the sticks around. Ardupilot would learn the inter-relationship of all the input channels and scale accordingly when in auto modes.
This might eliminate the need for several current parameters, like rudder mixing.

Thanks for the idea. It is a tempting plan but it doesn’t work for a few reasons.

I fly an 11 channel aircraft with 7 radio channels. You can’t do that if you put the mixing on the transmitter.

Look at the outboard aileron as a case. It has roll, differential, flap, airbrake and pitch mixed into it. None of the functions are linear. Some mixing is conditional on other channels. Unmixing that back to the stick command is not realistic.

How do you go about modifying the mixers? If you change your transmitter trim or mixing then the aircraft unmix is not in tune.

We don’t put quadcopter mixing on the transmitter and we never have. We never think of it that way. We started fixed wing autopilots by having them tweak the pitch and roll controls for us. We didn’t need any autopilot mixing. What we need now is more advanced and it demands different thinking.

Edit: Moving this discussion to a link below

@crashmatt the link you gave here seems incorrect, did you have a more appropriate one?

You are right about that link. I never did get the issue submitted. Here is the link:

You should check out my mixer at github
It is already quite powerful with access to system parameters which can be updated in realtime
Here is an example script


@skyscraper / Andy
I like this architecture and tridge is in favour of it. It results in a nice compact robust solution. Your implementation is particularly tidy,

It does run into trouble when you start modifying it through mavlink. I will explain why you might want to do that later. For now I will explain why it is a problem.

The core problem is when you decide to store the mixer when you have modified it. When you translate the -mix file into the mixer you loose information. You are pretty much compiling the .mix language into a machine code. The mixer is the state machine that runs the machine code.

Is it possible to reverse engineer machine code to get back to exactly the same source code?

Yes. We almost do this when debugging but it requires source code and debug data. Even then that is only one way. If the values in the machine code were changed then the source code needs to be automatically re-written, comments and all.
There may be a half way solution where comments and formatting are missing. You would get translation of variable names so that the saved .mix looks somewhat like the original. Maybe you could make a script that patches the original with the new version.

The next trick is how to do live mixer editing through mavlink. A gcs needs to know how to identify each of the different parts of the mixer. It also needs to know the geometry of the mixer you have loaded. Since you have a machine code table it might be possible to give each item an index identity so it can be modified.

And now to the why of it…

Correct me if I am wrong but it looks like you are flying gliders. They are tricky beasts to setup right. I am flying a 5m 11channel aircraft which takes much time to setup. I do have mavlink connected mixer tuning and I can’t imagine being able to do this any other way. This has been running on MatrixPilot for the past 5 years.

There is the option of writing the whole .mix file to the AP and rebooting. If you can imaging doing that 20 times per control surface you get an idea of how horrible it would be to use.

What happens when your mixer gets more complicated? For example, I have variable aileron->flap and aileron differential depending on flap and brake setting. It simply is not possible to define a mavlink parameter for each of these possibilities. At some point any tuning method that is unreliable, difficult to use or takes a significant amount of time will drive you quite crazy and you will stop using it.

The challenge: Finding a way to connect your solution to a mavlink tuning service and regenerating a .mix file.
If we can solve this we have what I consider a perfect system.

Well I am glad you like it :). It is early days and I am eager to get flying so I am looking at the simplest options to get in the air for now!

There are 2 parts which should be separately considered. The important one is the user interface which is the script. Ultimately that is the important bit to nail down e.g syntax and semantics ( and a comprehensive test suite).

You can then use pretty much any implementation. It is a black box. I am guessing the expression tree is pretty good, but can’t prove it is the best way. You would have to consult a compiler expert! In fact if you have room the easiest option is to use bison ( for example) for which there is a grammar . (In fact I havent tried implementing it to see how big it would be if implemented with bison so might be interesting to do that, but bison does parse the grammar at least)

“It does run into trouble when you start modifying it through mavlink”

Personally I would be wary to change the whole mixer in flight, but ultimately ( in my implementation) the runtime is only a pointer to an object “tree”. You could parse a new mixer script in another thread and then swap over to the new tree or even swap between them between calls to the mixer. That would be an “interesting” approach to debugging!

In fact you could add whatever optional debug info you wanted to the expression tree classes, since they are runtime polymorphic so you could easily swap them for debug versions, and so recreate the script that way. “I am a binary + and here are my children” etc)

rather than swap scripts,I was thinking more in terms of keeping with the one script object that was built at startup but allowing to modify a few user defined variables of interest. Using something like the input{Name} syntax, you could have a variable{MyVariable} which can be looked up by name and so updated by the back door on the fly . Surely Mavlink has a way to send text of the form SEND(UpdateUserMixerVariable,“MyVariable += 0.1”) or whatever?

If you wanted a record of what happened to the mixer then you could just play the text mods into a file as it is applied and replay them onto your original script manually or automagically, once happy?


oh yes, you go flying. I am very unlikely to do that this year so I have a year of software development time to use.

I had not explained myself properly when I described mixer “modification”. I meant to mean mixer tuning only. This does not include changing the shape of the mixer. It is only modifying discrete values, one at a time. I believe that your script is the best way to define the way mixers are connected. Rebooting between larger changes is not the end of the world.

Adding mixer naming and other data to the object tree means that you have to get at that data through the tree. That is quite hard work. It might be easier to generate an xml or json file with that information. The groundstation can then read the whole thing in one go and do what it likes with it. Does this make sense?

The mavlink interface becomes quite simple at this point. A few MAV_CMD messages and a MIXER_DATA message. Data is accessed through the indices provided by the debug data file.

This is starting to look very plausible.

I found this in the github description with your project

During building of the tree, constants are folded, producing a small, fast footprint for the resulting expression.

That is a little concerning since those folded constants might are the constants that require tuning.

Having a little walk through your codebase to see how it works.


Simply put anything that can be modified at runtime is not a constant
Constant folding is very useful because it reduces the size of the expression tree and also makes it execute faster.

If you want to modify something at runtime then make it a variable. The semantics of a variable in this context would be similar to a volatile value in C/C++. In fact volatile might be a better word than variable for an entity you can modify. It would convey the meaning better.

EDIT: Based on this I like the volatile keyword and have updated the readme accordingly

The constant folding works by interrogating child nodes ( who in turn interrogate their childern. ) as to whether they are constant. ( If the answer is no then no folding is done on that node). This is done as the tree is built so that heap memory is freed ASAP so it can hopefully be reused for other nodes in the tree so reducing the overall memory used

I should also mention some of the other things I hope to implement.

First is Assertions. These will be writer defined checks that are made in global namespace ( but not in the mixer function) and if they fail the tree will not be created. In the airspeed mixer example. It should be asserted that the ARSPD_MIN value is greater than zero and so on e.g

assert(input{ARSPD_MIN} > 5.0); // if assert is false mixer build fails

I will have to think how that works with variables. I may go with evaluating and forcing anything in global namespace constant before the asserts are run, else the asserts dont carry as much weight. So you would then have to declare any variables in the mixer loop and you would be running UNSAFE_MODE :slight_smile:

The other thing is curves. To express a curve you would just use x,y pairs

my_curve = [a,b],[c,d],[e,f],[g,h];

basically representing a line chart. To evaluate it you just call (EDITED)

myvalue = my_curve(my_input); 

Which just sees the input as the x position on the graph and returns the y position
You then have the something equivalent of OpenTx curves You could also have some inbuilt curves

What you call curves are what the rc community knows as multipoint mixers,
normally 5 point or 7 point. I use these in preference to gain and
offset. It is easier to understand what you will get when defining points.

It is also possible to implement mixers with very steep edges, to the point
of being a switch. This is nice for getting exactly the desired pattern
with crow brakes. My aircraft has spoilers (which are more trouble than
its worth) which deploy during a phase of the crow brake deployment. The
different movements have different effects on pitch trim. The multipoint
mixers make it possible to trim properly.


Cool. If they can be used to make multiposition switches, even better

I see what yo say re multipoint mixers I like the name “curve” though. Nice and concise and catchy. What do you think?

I decided to change the Volatile syntax. Now to define a volatile symbol, you just add volatile in front of the symbol name when it is defined. This means that you can just add or remove volatility to a symbolw ithout having to rewrite anything else in the script.

EDIT: also added Curves

potatoes… potatoes. If you like a different name go with that.

To make a mavlink interface I need a few things:

  1. A lookup table to volatile variables so they can be modified
  2. A file or table describing the mixer functions
  3. A file or table describing the mixer configuration ie. what each function is, what arguments it takes and where it puts its output

If I can get a screen dump or file output for the contents of symtab, funtab and mixer it would help me understand everything. If you don’t have this already I will attempt to write it myself as a learning exercise.

The external mixers such as px4io and uavcan can be quite resource limited. They don’t have space for any of the human readable mixer naming. We might need a function cutdown option of what you have now.


So basically an API to get at the mixer data?
Probably also switches to turn off constant folding, to not delete the symboltable etc
First though I need to make the current repo into a library module and the Taranis joystick just an example that uses the library, so I will get on with that now.

@skyscraper What do you do for functions with multiple outputs?
[out1, out2] = foo(in1, in2)
A hard coded v-tail mixer would look like this. I know you would build it from pieces but someone might want an easy function for it.