ArduPilot Thrust Stand


About the Project

This is a fun project that I have been working on, for the past few months, that I would like to share with everyone. I have been designing a suite of tools to help members of the community make a more informed decision around powertrain selection and to assist in capturing thrust expo data for tuning copters and such.

Central to these tools is an ArduPilot based thrust stand. This thrust stand has the following features:

  • Logging: Throttle, thrust, torque, voltage, current, motor commutations (RPM), time stamp.
  • ESC Logging: If using a BL Heli ESC then it also logs ESC current, ESC RPM, ESC temp, ESC Voltage.
  • Throttle ramp mode: Gradually raises throttle to maximum (set as a param), pausing at 10 increments to capture steady-state response.
  • Throttle transient mode: Ramps throttle to ‘hover throttle’ and then proceeds to run through a table of step inputs about the hover throttle to capture transient behaviour. (The implementation of this still needs refining).
  • Over-current protection: Set a parameter value for max current. When exceeded the throttle is zeroed and the system stops to prevent damaging ESCs and motors on test, with the screen and lights informing the user.
  • Display: Addressable LEDs used for throttle bar. OLED display used for on-screen feedback of throttle, thrust, torque, current, and voltage.
  • Safety: Building on ArduPilots already proven motor safety, ‘vehicle’ arming and disarming, is used just in-case the script dies, cutting the motor. Pendant ‘dead-mans’ button for operating the motor.
  • Telemetry: A WiFi hotspot makes it easy to use a GCS for live remote telemetry and control. Plus using MAVFTP makes data retrieval very easy.

This project is totally open source. All of the code, CAD, and details of the components used are going to be shared. Just bear with me whilst I collate all of this information and make it available. All will be done through this thread.

Project Objectives

Perhaps the best way to help others understand some of the decisions I have made along the way is to explain what I wanted to achieve:

  • Develop a set of tools that will be useful for the AP community (and perhaps wider).
  • Make the project accessible. More specifically, accessible to build the hardware at a reasonable price. There are a lot of 3D printers in the community, hence a heavy reliance on this method of manufacturing.
  • To use AP’s scripting to offer an example of a larger scripting project that is a bit outside of the examples provided thus far to hopefully encourage more people to have a go with the friendly development environment that scripting offers.

This Blog

As and when I have chance, I am going to keep adding to the information here through a number of posts. Broadly I plan to follow this order:

  • Intro of the project: This post
  • Hardware: An overview of all the parts I used and why.
  • Manufacture: How the bits I designed are made.
  • Data Processor: An introduction of how to access, use, and contribute to the post-processing tool I have been making.


Something I am quite pleased about with the way this project turned out is that there is a lot of flexibility. Not everyone will necessarily need/want torque data for example, so they can easily get one of the low-cost thrust stands off of bang good and plumb the load cell from that into this system to get more data and better automation. That makes the project way more accessible with just some 3D printing and soldering and your away.

Mayatech mt10 10kg motor thrust tester propeller power tension measurement for rc model racing drone Sale -

The Back Story

Talking of the Mayatech thrust stand, that is in fact how this project began. I got one of these stands and stripped off the LCD screen and buttons and started building up from there:
Gradually I added more functionality, adding in the LED bar, voltage and current monitoring, OLED display, and RPM from electrical commutations:

It was after this that I started working on capturing torque. This necessitated designing a new stand. I did try a couple of different layouts of using load cells to get both thrust and torque. The issue I regularly run into was that the data wasn’t coming out very clean. It would either get some noise from vibrations due to mass imbalance on the motor/prop or there would be cross-coupling between the two load cells. Now, I could have spent more time in decoupling the load cells in the script or in the postprocessor, as that is how many thrust stands work. However, I decided to go down the route of mechanically decoupling the thrust and torque sensors through the use of bearings and bushings. I was quite pleased with the result I was getting. This is the design of the thrust stand that I ended up with:

With this design the motor is attached to the shaft. The shaft is free to translate along and rotate about its axis. The torque load cell is clamped and bolted through the shaft. The lower bearing provides a single point of contact so that a pure bending moment is applied to the sensor. Inside the long black section at the back, two thrust bearings and a bushing are used to allow rotation but transfer the thrust load to the load cell at the back.

Despite all that I have done to reduce friction, there will no doubt be some hysteresis in the system. I counter that by always running a ramp up and a ramp down to a) understand how bad the hysteresis is and b) be able to remove the effects of it in post-processing. The two graphs below show an example of the outputs I get for thrust and torque in a throttle ramp test:
There is a ramp up and down in that data set, so I think you will agree that the hysteresis is minimal. As for repeatability, I have run countless tests on this rig now and always found very good agreement between repeat runs, the only difference being the effects of slightly lower voltage in subsequent runs.

Finally, this led me onto adding a new throttle mode to capture transient behaviour of a prop/motor combo. In this mode, the throttle is slowly ramped to the throttle setting given by the MOT_THST_HOVER parameter. Then a series of step inputs are input about the hover throttle before the throttle is gradually ramped down to zero again. Here are some example outputs that I have gotten for this throttle mode:
This mode still needs some finessing in terms of usability as it currently relies upon the user to change the throttle step inputs within the script.

Output Data and Post Processor

The data captured by this script is dumped to a *.CSV file so the bar to entry for processing the data is very accessible. For example, it is easy to use the output in the already existing google sheets expo fitting tool.

There is not a lot I can say about post-processor at this point as it is very much a moving target and still needs a lot of work. Its functionality so far is:

  • Importing of all *.CSV files in a directory, for comparison.

  • Auto run detection, to split multiple throttle ramp’s from a single file into multiple instances for easy comparison.

  • Plotting of any logged variable against any other variable

  • A number of filters for cleaning data up

  • A crude coax grouping approach that allows you to add different data instances into one net outcome as if it were a coax on test.

  • MOT_THST_EXPO fitting tool

This tool is written in Python and the GUI is done in TKinter. This is what it currently looks like:

About the Thrust Stand Code

The thrust stand code is written in Lua. The code thus far can be found in this WIP PR: #16813

The top section of the code is a port of the C library from SparkFun into LUA, to be able to make use of the NAU7802 amplifiers on the I2C bus. This script therefore uses @IamPete1 's I2C scripting PR (#14276).

The lower section of the script is then the actual thrust stand code.

This script does depend on a few other PRs for scripting bindings before it will work on AP master:

Finally, this PR is marked as WIP at the moment as I am still chasing out one bug, which I don’t believe is actually a fault of this lua script. Basically, I am using a Matek F765. The amplifiers have the same address and are therefore on two seperate I2C busses. For some reason the amplifier for the thrust load cell ‘looses’ data and LUA gets nil values in return. I do have the OLED screen on the same bus, however I have removed this and the problem still occurs. I have also ruled out EMI as both thrust and torque I2C buses are run next to each-other and the fault always occurs on thrust and not torque. Plus both lines are run through a grounded metal braid. Also, I have swapped the thrust and torque amplifiers to rule out a faulty amplifier. This is an intermittent problem so doesn’t always cause issues. Turning down the sampling rate reduces the likely hood of the issue happening, but I am pretty sure thats just because it is reducing the traffic on the bus. I think it might be a race condition or DMA buffer issue, but I am getting well out of my area. So, if anyone has any ideas/pointers on how to debug this I would love to hear them.

Thrust Stand in Use
A video of me using the thrust stand for some 5 inch coax:

Demo of Overcurrent Protection
A video demo of the overcurrent protection functionality. The parameter has been set very low to trigger the protection for the demo.


Very nice ! I am sure this will be useful for many users

That’s really well-made and interesting!
May I ask what is the purpose of the 2nd propeller in front of the propeller under test?

@Georacer thanks :grin:

The test with the two props is a crude coax setup. Only on motor/Prop is being measured for thrust and torque. The other motor/Prop that is not being measured is simply there to provide the right aerodynamic interactions. I do one test with the ‘bottom motor’ being measured, then I swap them around so that the ‘top motor’ is being measured. The combined effect is then added together in thrust to get the total coax thrust.

To show you some of the data I got out of that setup: The below shows the thrust for the two motors. The Orange line is the motor ‘on the top’ and the blue line is the motor ‘on the bottom’

These can then be summed to give the resulting total thrust:

1 Like

I like this very much!


Very nice!

Outstanding attention to detail & great features.

1 Like

Is the thrust measurement bi-directional for this case? (co-axial)

As in the bottom motor will be in tractor confguration & the top motor in pusher configuration

Yes exactly. The load cells are bi-directional. You just get +/- thrust and torque to give the direction. The positive direction is set during calibration. Then I have put a little tick box in the post-processor that allows you to invert negative thrusts and torques for easier comparison.

1 Like

Thats awesome. Question: Im not quite sure how the torque cell is connected to the shaft. How is the torque being measured, if the two bushings are rigidly connected to the rest of the frame? Wouldn’t this restrict the direction of motion needed to measure any torque?

The motor is connected to the shaft. The torque load cell is also connected to the shaft. The bushings allow the shaft to both rotate and slide in the direction of the shafts axis. So any motor torque would cause the shaft to spin, if it weren’t for the torque load cell preventing the shaft from spinning. Critically, the torque load cell is the only thing that resists the shaft from spinning, hence why we can measure the reaction from the motor torque. I hope that makes sense. I will be sure to post up an animation of all the Fusion 360 joints, when I get to explaining the construction, to help everyone see how it works.

Yes, I am also not sure about the torque measure. First, I think it is more useful torque/rpm. This is a graph of a manufacturer with the curve torque/rpm

In electric motors the torque is máximum with minimum rpm, and I think you are getting a measure of the energy of the rotating system.

In adition to my post I think that your device is awsome and very well finished.

very nice!
I like this very much!

For those that are interested here is the link to the talk I gave at the ArduPilot Conference about this project:
ArduPilot Thrust Stand by Matt Kear - YouTube

For those that have been asking about how the torque measurement works, if you skip to 22:24 I talk about the torque load cell specifically.

1 Like

Hi @IAMMATT , and anyone else doing thrust measurements :slight_smile:
We’ve had some debate about Flame ESCs providing some form of thrust linearization - or not…

Your mission, should you choose to accept it, is to measure a T-Motor Flame ESC compared to some ordinary ESC (such as equivalent Hobbywing Xrotor) in regards to thrust expo.
It may be that you don’t even need to use a T-Motor motor and prop for tests, because we probably just want to know how different the ESCs are in this case, and if the ESC is doing anything to the thrust curve.

I think there’s lots of cases where MOT_THST_EXPO,0.2 is in use and working fine. Some say the Flame ESCs don’t do linearization and the normal calculated MOT_THST_EXPO for your prop size should be used. It would be great to put this debate to rest, or at least give it some actual data.

Hi Shawn,

I have never seen data for the flame Esc’s. However I have seen data for the t-motor alpha. Esc’s (both with t motor motors and with other brand motors). The Alphas also claim to do thrust linearization. I can tell you with certainty that they do not linearize the output. So my money is that the flames do not also.

Hi Matt, you really made a very impressive and good job.
I purchased few week ago the same Thrust Stand you started from (Mayatec MT10 Pro) and I found that the most boring issue is to write manually the measuring data (considering also the limited time due to the battery service), so looking for someone that already solved this issue, I’ve seen your post and have been very well impressed.
Now, I am not interested measuring the torque because I pilot only airplanes models, so I would be interested to do something like what you made at the beginning (the thrust stand capable to acquire thrust, voltage, and RPM from electrical commutation with the capability to input the voltage manually or with a defined step sequence and the OLED display with the capability to store data or send them to a PC.
I have not (as I suppose you had not too) the Thrust Bench pinout of the thrust reading display and/or at least of the strain gauge installed on the measuring beam.
Could you help me to make something similar to what you made at the beginning of this job? I have some knowledge and practice in mechanics, electronic and informatics also if I never worked on the Arduino World, so I hope that, with the right instructions, I could do what I have in mind (of course you help will be essential to reach my goal).

Hope that this is the right place to write about this issue otherwise please, let me know how contact you.

Thank you in advance.I will appreciate very much if you will be available to help me to transform my wish in something real.


Hi Matt, very nice project. Have you released the CAD files for the stand?

1 Like

Just posting this here for anyone who wants to replicate:

The key bit that people will need is the Lua script to get a ArduPilot based thrust stand. The lua script can be found here:
ardupilot/libraries/AP_Scripting/examples/Thrust_Stand.lua at Thrust_Stand_XL · Gone4Dirt/ardupilot (

This script is used for interfacing with this amplifier:
SparkFun Qwiic Scale - NAU7802 - SEN-15242 - SparkFun Electronics

The script is flexible enough to be used for both thrust only or thrust and torque. This is achieved through the THST_ENBL_TORQ param to use torque measurements.

The point of this script is that we can use any ArduPilot supported sensors or ESC telemetry to add measurements into our test data.

For many, a disadvantage to this method is that it stuffs all of the logged data into ardupilot *.bin files which means that for optimal ease of use, users will need to be comfortable with parsing bin files and getting the data out of them. I use Pymavlink’s parser for example. An alternative option is to export the data to matlab *.mat or *.csv using mission planner. It adds another step to the analysis process but may be easier for many users.

An idea to avoid the bin file, you could write the required data directly into a csv file with a lua script. Gives you the advantage of a better time resolution and avoids the parsing.