Stavros’ notes

Welcome to my notes.

This site is autogenerated from a bunch of Joplin notes. I wrote a small script to read the notes, export them, and generate a static site. If you want to use the script and generate such a site for yourself, feel free to fork my repository:

Just run ./joplinexport on your computer, it will read the database and create a site like this one and upload it to GitLab pages. Also, the build and move_html_to_dir scripts might be of interest.

Otherwise, enjoy my notes!

Last updated on November 20, 2021. For any questions/feedback, email me at


Click on a link in the list below to go to that page:

  1. A simple guide to PID control
  2. E6000 hinges
  3. FPV frequency chart
  4. Getting uninverted SBUS on a no-name FrSky-compatible receiver
  5. Getting uninverted SBUS/SmartPort on the FrSky XSR receiver
  6. INAV tuning tips
  7. Miscellaneous
  8. Omnibus F4 V3 pinout
  9. Omnibus F4 pro servo diode
  10. QGroundControl to Mission Planner conversion script
  11. Transmitter external module pinout
  12. Transportable C1 Chaser


Click on a link in the list below to go to that page:

  1. ArduPilot recommended settings
  2. ArduPilot setup checklist
  3. Building ArduPilot
  4. Configuring a switch as a relay
  5. DJI FPV configuration
  6. Miscellaneous notes
  7. Reverse thrust
  8. TECS tuning calculator
  9. Transfer config between craft
  10. Tuning the TECS

ArduPilot recommended settings

This section contains some recommended settings for ArduPilot. Nothing is set in stone, these are just some defaults I’ve found to work well.


GPS_RATE_MS=100   # 10 Hz update rate.


SERIALn_PROTOCOL=23  # Crossfire/ELRS.
RC_OPTION=800        # 5 - Arming check throttle.
                     # 8 - CRSF telemetry passthrough.
                     # 9 - Suppress CRSF mode/rate message for ELRS.


30% expo is a good starting point:



INS_GYRO_FILTER=60     # Faster gyro updates.
SCHED_LOOP_RATE=100    # Faster scheduler updates.

Servo update rate

If you want a higher servo update rate (because of digital servos), it is probably better to set the scheduler loop rate to the frequency you want, and enable ONESHOT on the servos:

SCHED_LOOP_RATE=200   # As above.
ONESHOT_MASK=6        # Change to whatever channels your servos are on.

Last updated on December 31, 2021. For any questions/feedback, email me at

ArduPilot setup checklist

This is a short guide for setting up ArduPilot on a flying wing. I use an Omnibus F4 that was previously set up for INAV (so motor on 1, elevons on 3/4), so most of this guide will be geared to that. If you use a different controller, your mileage may vary.

You should keep the full list of ArduPilot parameters open, for your reference while tuning.

Helper utility

I have created a utility that lets you easily get/set/backup/restore parameters from the command line. It’s called Parachute, and you can download it here:

Building ArduPilot

See Building ArduPilot for instructions on how to build the latest version.

Hardware setup

The values in this section are specific to the Omnibus F4, but the settings aren’t, so you’ll usually need to adjust your outputs to your specific configuration but you probably won’t need to skip many of the steps here.

  • Connect GPS to UART 6 (SERIAL4). You don’t need to do anything else for GPS, it should work out of the box. If it doesn’t, set SERIALn_PROTOCOL=5.
  • Change the FC’s orientation with AHRS_ORIENTATION and monitor the artificial horizon to see if it moves correctly.
  • Calibrate the accelerometer. “Forward” here needs to be the forward direction of the plane, not the arrow on the FC.
  • Connect Fport to a UART. I chose UART 3 (SERIAL2). If you want to use UART 1, you should set the RC input jumper to PPM on the F4 to disconnect the SBUS inverter from the pin.
  • To get Fport working with UART 3, you need to set BRD_ALT_CONFIG=1, to get UART 3 to act like a UART instead of I2C on the Omnibus F4.
  • Set the following for Fport on UART 3:
  • Once Fport works, reverse the elevator with RC2_REVERSED=1.
  • Set up your servo functions and trims:
    SERVO1_FUNCTION=70  # Throttle
    SERVO3_FUNCTION=77  # Left elevon
    SERVO4_FUNCTION=78  # Right elevon
    All these values are necessary, because usually the SERVOn_TRIM won’t be at 1500.
  • Set SERVO_BLH_OTYPE=4 for DShot150 and SERVO_BLH_MASK=1 to enable it for the motor.
  • Set COMPASS_ENABLE=0 if you don’t have a compass, otherwise calibrate it (not detailed here).
  • Set TERRAIN_ENABLE=0 to get rid of the terrain warning.
  • Set the FC’s pitch relative to the body with AHRS_TRIM_Y and check that FBWA mode flies level.
  • If you don’t use logging, set LOG_BACKEND_TYPE=0.
  • Check the preflight errors to warn on, though usually leaving it set to “all” is fine.
  • Set up the OSD (Mission Planner has a very nice UI for that). Keep in mind that ArduPilot’s airspeed and windspeed estimation are quite good, so you may want to add those even if you don’t have an airspeed sensor. You may also want to set up multiple screens, I use a potentiometer to switch between the four different screens of the OSD:
    • One with everything on (for debugging), which is also set as the OSD_ARM_SCR/OSD_DSARM_SCR.
    • One with the artificial horizon, system messages and some basic info like RSSI, battery, ground speed and altitude.
    • A minimal screen with just system messages and battery/RSSI/speed/altitude.
    • A screen with just system messages, for when I want to enjoy the scenery.
  • Set your radio channels to AETR and run the radio calibration in the calibration section of ArduPilot.
  • Add a killswitch to the radio that overrides the mode to manual and the throttle to 0. This way it’s really easy to kill the motor right away, but you still need to go through the arming procedure to get the motor running (thanks to Michel Pastor for this great idea).
  • Set up modes, possibly having switches override the mode channel to the mode you want.
    What I do is set a given channel as the mode channel, and make that channel always output -100% on the radio. Then, I set up channel overrides for each switch, keeping in mind that overrides in OpenTX are executed in order (so the bottom override has the highest priority).
    That way, I set MANUAL/ACRO/FBWA to be lowest priority (on the same switch), then CRUISE to override those, then LOITER, RTL in that order. Finally, I add AUTO to a switch on its own channel.
    Keep in mind that whatever mode you have on its own channel might be overridden if you flick a different switch. Unfortunately, the way the mode system in AP works, there’s no good way to have a list of prioritized modes, which would be ideal though now I have opened a PR to extend the modes to 12, which solves this).

Auto modes

  • Set SERVO_AUTO_TRIM=1 so the aircraft trims itself while flying.
  • Set FS_SHORT_ACTN/FS_SHORT_TIMEOUT/FS_LONG_ACTN/FS_LONG_TIMEOUT. I tend to disable the short action and set long to RTL.
  • Set FLIGHT_OPTIONS+=16 so the aircraft climbs first before starting to return to home.
  • Set FLIGHT_OPTIONS+=64 so the aircraft doesn’t oscillate on auto takeoff without an airspeed sensor.
  • Set ACRO_LOCKING=1 to avoid drifting when you aren’t moving the sticks.
  • Change AUTOTUNE_LEVEL according to how aggressive you want the tune.
  • Set ACRO_PITCH_RATE/ACRO_ROLL_RATE according to your craft.
  • Set THR_PASS_STAB=1 so you have total throttle control in ACRO/FBWA/STABILIZE.
  • Set ARSPD_FBW_MIN/ARSPD_FBW_MAX to the minimum and maximum airspeed you want auto modes to fly (see the TECS tuning guide below for details).
  • Set MIN_GNDSPD_CM so the craft makes an effort to return even under high winds. WARNING: Might make throttle pulse or have other unwanted side-effects.

Auto takeoff

  • Change TKOFF_THR_MAX to the desired max takeoff throttle.
  • Change TKOFF_ALT to the altitude you want takeoff to reach.
  • Set THR_SUPP_MAN=1 so you can manually set the autolaunch “idle” throttle (before the throw).
  • Set TKOFF_THR_MINACC=18 for the takeoff throw to activate takeoff with a minimum of 2g.
  • Set TKOFF_LVL_PITCH to your desired angle (20 is a good value).
  • Set TKOFF_THR_DELAY to the number of deciseconds that you want the motor to wait before it starts up.
  • Potentially set TKOFF_THR_SLEW=-1 to make the throttle spin up faster.

See the recommended settings page for other recommended defaults.

In the field

  • Run an autotune.
  • Fly in FBWA and see if you’re gaining/losing altitude. Pitch up/down to fly level, check the pitch on the OSD, and use the formula old_value+pitch*π/180 to get the new value for AHRS_TRIM_Y (in radians).

(Many thanks to Michel Pastor for his help with everything in this note.)

Last updated on December 23, 2021. For any questions/feedback, email me at

Building ArduPilot

Because building ArduPilot is a bit complicated, I’ve written a short script that uses Docker to build AP in a controlled environment.

Copy it from here, save it to a file called in the root of the ArduPilot repo, and run it with <your board>. Output files will be stored in build/<yourboard>/bin/, and you can flash them with the INAV configurator by putting your board in DFU mode and uploading the arduplane_with_bl.hex file.

Here’s the script:

#!/usr/bin/env bash

set -euox pipefail

if [ $# -ne 1 ]
    echo "No board supplied, run as ./ <board name> or ./ list"
    exit 1


cd "$(git rev-parse --show-toplevel)"

git submodule update --init --recursive

git checkout Dockerfile
echo "RUN pip install intelhex" >> Dockerfile
echo 'ENV PATH="/home/ardupilot/.local/bin:/usr/lib/ccache:/ardupilot/Tools/autotest:${PATH}"' >> Dockerfile
cat Dockerfile

docker build . -t ardupilot
git checkout Dockerfile

# We need to update the PATH with the location of the ARM EABI inside the Docker
# container, so we write a script that handles this and the actual building.
cat <<EOF >
#!/usr/bin/env bash

set -euox pipefail

export ARM_EABI=/opt/\$(ls -1 /opt/ | grep gcc-arm-none-eabi)/bin/

./waf configure --board="\$1"
./waf build

chmod +x ./

docker run --rm -it -v "$(pwd)":/ardupilot ardupilot ./ "$BOARD"


Last updated on September 07, 2021. For any questions/feedback, email me at

Configuring a switch as a relay

If you want to connect a relay of some sort (something that accepts a low/high signal, like a camera control) to a PWM output (the servo outputs), you need to do a few quick things. The actual numbers will vary depending on your FC, but here’s what worked for me with a Matek F405-Wing:

  1. Set the channel you want the relay to trigger on as a controller for the first relay (here I’ll assume you want to control the first relay on channel 11):
  2. Set the pin number for the relay you want to control. This is a bit fuzzy, it depends on your flight controller, but try a few out. This is what worked for me, for S6 on my F405-Wing:
  3. Set a servo to act as a GPIO output. I’m assuming here you want SERVO6, though I’m not quite sure how the servo selection maps to the RELAY_PIN selection above. For me, AUXOUT6 and SERVO6 worked:

If you’re amazingly lucky, you should be all set. If not, you need to play with the 50 in the RELAY_PIN parameter and the 6 in the SERVO6_FUNCTION until something works.

Last updated on September 11, 2021. For any questions/feedback, email me at

DJI FPV configuration

If you’re using the DJI FPV system, here’s the relevant configuration you need to set:

  1. Set OSD_TYPE=3.
  3. Create a text file called naco.txt on the SD card of the Air Unit with the text 1 in it to unlock full power.
  4. Create a text file called naco_pwr.txt on the SD card of the goggles with the text pwr_2 in it to unlock more full power.
  5. Set “Custom OSD” to “on” in the goggles menu.
  6. Arrange your OSD elements how you like them.

That’s it!

Last updated on December 31, 2021. For any questions/feedback, email me at

Miscellaneous notes

These are random AP-related notes that wouldn’t fit anywhere else:

DMA on the Matek F405-Wing

If you want to get DMA on UART3 of the Matek F405-Wing FC (or, more relatedly, the Racerstar F405, because UART1 is Bluetooth there), you can open libraries/AP_HAL_ChibiOS/hwdef/MatekF405-Wing/hwdef.dat and comment out line 92ish, where PA15 is defined.

That will enable DMA on UART3, at the expense of disabling the LED pad.

Last updated on December 31, 2021. For any questions/feedback, email me at

Reverse thrust

To set up reverse thrust (for higher braking when landing, for example), follow the steps below:

  • Set your BLHeli-compatible ESC to “Reversible soft” and make sure you’re using DShot.
  • Set THR_MIN=-100.
  • Set SERVO_BLH_RVMASK=1 (or whatever channel your motor is on).
  • Set RC9_OPTION=64 for the reversing switch on channel 9 (or whatever channel you want).
  • Set USE_REV_THRUST=0 to disable reverse thrust on all auto modes.

You’re done.

When flipping the switch, throttle will reverse, so your plane will slow down instead of speed up the more you throttle up. Be careful not to stall or otherwise hurt your craft, I don’t recommend going over 20-30% reverse throttle.

Last updated on December 31, 2021. For any questions/feedback, email me at

TECS tuning calculator

To use this calculator, first follow the steps in Tuning the TECS.

Fly straight

Fly up

Fly down

Fly down more

Run this command in a terminal, making sure you have Parachute installed:

(Please fill out the values above first)

Last updated on September 07, 2021. For any questions/feedback, email me at

Transfer config between craft

This is the regex I use with Parachute to transfer between planes only the parameters that are transferrable (ie non-plane-specific):


This will transfer things like the OSD settings, flight modes, failsafe options, etc etc, but will leave things like PID tuning alone. Use it to set up a new plane by copying over settings from an older plane.

Last updated on September 07, 2021. For any questions/feedback, email me at

Tuning the TECS

To tune the TECS, a helpful resource is the official TECS tuning guide. Make sure you have run an autotune beforehand, and continue with the tuning below.

In tuning, there are three stages:

  • Prepare to measure
  • Take measurements in the field.
  • Set parameters on the bench, based on your measurements.


  • Set LIM_PITCH_MAX=4500 (centidegrees), or something similarly high. This is the maximum pitch you’ll be achieving in FBWA, and you don’t want to be limited by this while trying to tune.
  • Set LIM_PITCH_MIN=-4500 (centidegrees) or something similarly low. This is the minimum pitch you’ll be achieving in FBWA, and you don’t want to be limited by this either.
  • Set THR_PASS_STAB=1 to avoid mapping your throttle to a curve in some modes. This is important because you want a raw (non-remapped) throttle value when measuring.
  • Add the airspeed and pitch angle elements to the OSD so you can actually take the measurements.
  • Enable throttle battery voltage compensation with FWD_BAT_VOLT_MIN/FWD_BAT_VOLT_MAX. Set the max to 4.2 * num_cells and the min to 3 * num_cells for Li-Ion and 3.5 * num_cells for LiPo batteries. This makes your measurements more accurate, as a partially-depleted battery won’t make your motor run slower and skew the results.

In the field

You should perform the measurements in four stages, all in the FBWA mode:

Fly straight

Fly straight and note down:

  • The maximum speed you want to be flying at (in km/h).
  • The throttle percentage at that maximum speed. Use the stick position, not the OSD item.
  • Start a turn at the maximum bank angle (full roll deflection to one side) and note the slowest speed you can fly at without stalling.
  • Fly straight at a speed 15% higher than the stall speed from the previous step, and note that speed. This is your trim speed.
  • Note the throttle percentage at that speed. Use the stick position, not the OSD item.
  • Turn throttle to 0 and pitch down a bit so you don’t stall. Note the minimum amount of down-pitch required to keep you from stalling (this should only be in the 1-3 degree ballpark).

Fly up

Set the throttle stick to the maximum throttle percentage from the previous step and start slowly pitching up until your airspeed equals your trim speed from the previous step. If you’re higher than that speed and need to climb more, change LIM_PITCH_MAX to something higher and try again. Note down:

  • The pitch angle (in degrees).
  • The vertical speed from the variometer (in m/s).

Fly down

Set the throttle to 0 and start pitching down until your airspeed equals your trim speed from the previous step. Note down:

  • The vertical speed from the variometer (in m/s).

Fly down more

Keep the throttle at 0 and pitch down until you reach your desired maximum speed from step 1. If you’re lower than that speed and need to pitch down more, change LIM_PITCH_MIN to something lower and try again. Note down:

  • The pitch angle (in degrees).
  • The vertical speed from the variometer (in m/s).

You’re done with this step.

On the bench

After you have the above measurements, you’re ready to tune things. You can use the automatic calculator:

TECS tuning calculator

Otherwise, you can do things manually, following the steps below, but you should really use the calculator instead.

For the level flight measurements:

  • Set ARSPD_FBW_MAX (m/s) to something a bit less than the maximum airspeed you achieved in level flight.
  • Set THR_MAX (percentage) to the throttle percentage at max speed.
  • Set ARSPD_FBW_MIN (m/s) to the slowest speed you could turn at without stalling (maybe go a bit higher for some margin).
  • Set TRIM_ARSPD_CM (cm/s) to your trim speed.
  • Set TRIM_THROTTLE (percentage) to your trim throttle percentage.
  • Set STAB_PITCH_DOWN (degrees) to the pitch angle that keeps you from stalling.

For the ascent measurements:

  • Set TECS_PITCH_MAX (degrees) to the pitch angle you measured.
  • Set TECS_CLMB_MAX and FBWB_CLIMB_RATE (both in m/s) to the climb rate you measured.

For the descent measurements:

  • Set TECS_SINK_MIN (m/s) to the descent rate you measured.

For the max descent measurements:

  • Set TECS_PITCH_MIN (degrees) to the pitch angle you measured.
  • Set TECS_SINK_MAX (m/s) to the descent rate you measured.

That’s it!

Advanced information

This is some more advanced information on tuning the TECS:

  • If you want more altitude precision and more responsive control, you should lower the TECS_SPDWEIGHT parameter value below 1.
  • A right KFF_THR2PTCH value is crucial for the TECS to work correctly without pitot.
  • The THR_SLEWRATE value should be set so that the plane doesn’t lose airspeed when you yank the pitch stick to TECS_CLMB_MAX degrees.

Last updated on December 18, 2021. For any questions/feedback, email me at


Click on a link in the list below to go to that page:

  1. Build notes for the FT Mighty Mini Arrow
  2. Mini Drak build condensed instructions

Build notes for the FT Mighty Mini Arrow

These notes are a condensed version of the FT Arrow build video.



  • Do an “A” fold on the spars and glue, stop 15mm from each edge. Use a triangle to make sure the spar folds are perpendicular.
  • Open the servo hole.
  • Cut the bevels, double on wing and single on elevon (on the elevon side).
  • Add a thin ribbon on glue on the bottom of the elevon hinge for strength, and scrape almost all of it off.
  • Remove servo pocket from the wing.
  • Fold the wing with the bottom on top, to curve the leading edge without crinkling the airfoil score cuts.
  • Cut the side pods if you aren’t going to use a center pod.
  • Glue the side pod hinges.
  • Cut the main pod space on the top of the wing.
  • Skewer the wing score cuts.
  • Line up the spar’s servo hole onto the wing and glue onto the top side.
  • Glue the airfoil’s score cuts and fold the wing so the score cuts are glued up.
  • Cut the excess spar.
  • Probably put the servos in now, to avoid having to make a hook later.
  • Glue the leading edge, bottoms of the spar, and the end of the trailing edge, and press closed.

Joining the wings

  • Tape the wings together at the bottom, glue them together in the middle, lay them down and wipe the excess glue.
  • Cut the excess edge of the nose.

Center pod

  • Pop out the foam tabs on the wings, where the center pod will go.
  • Pop out the tabs on the center pod.
  • Do an “A” fold on the bottom plate.
  • Fold the little edge of the top of the center pod over (and/or add tape).
  • Glue the center pod on. The backs of the wing should both be at the same height. Note that still be open/exposed, not glued down. FT leave them like that, but I like to close them up with some tape at the end so junk doesn’t get into the wing.
  • Install the control horns and servos (I use epoxy for the control horns as they tend to get ripped out with just hot glue).
  • Use the reflex checker foam to calibrate the wing’s reflex.
  • Add a ziptie to the control rod so it doesn’t bend.

Power pod

  • Install the motor onto the power pod and install the power pod. You probably don’t need to glue this, just make sure it’s tight.
  • Remove the foam from the sides of the nose.
  • Do a “C” fold on the back bit (and probably add some tape).
  • Carefully bend the nose.
  • Test fit it and glue the front part.
  • Use more tape to secure the front and sides.
  • Add some tape so you can pull the top open.
  • Add some glue to the bottom of the top hatch so it catches and secures on close.


  • Only cut the top part of the wing, parallel to the bottom.
  • Line up the reference line on the winglets and glue (the front tip of the winglet should be flush with the leading edge).


  • The rest is left as an exercise to the reader.

Last updated on November 27, 2020. For any questions/feedback, email me at

Mini Drak build condensed instructions


  1. Håvard’s Mini Drak build video
  2. Team Legit’s build video

To start building:

  1. Nubs:
    1. Cut off all the nubs with a fresh blade, and sand the remainder down with a sanding block to make it flush with the rest of the foam.
  2. Motor:
    1. Cut the top left and right corner of the motor mount off, so it doesn’t conflict with the screws in the foam.
    2. Use only a hacksaw to open a slot in the foam for the motor mount to go through.
    3. Insert the mount into the slot, test it out and remove it again.
    4. Apply ample glue both inside the slot and on the motor mount, both on the sides and the top.
    5. Insert the motor mount into the slot, put a hard surface (like a hardcover book) under the foam, another hard surface at the top, add some weight or clamp and leave to cure.
  3. Thick spars:
    1. Remove the spars from the sleeves and keep the sleeves. Do not cut the spars.
    2. Insert the sleeves in the wings and measure them out. Mark the point in which the sleeve sticks out of the wing and cut with a dremel outdoors.
    3. Trim the sleeves for the main fuselage.
    4. Use some sandpaper wrapped around the spar to lightly scuff the body where the spars will go.
    5. Put the rear spar into the sleeve, to help you push the sleeve down into the foam. Make sure it’s pushed down all the way to the bottom.
    6. Check that the wings are straight.
    7. CA glue the sleeve into the body while making sure it’s flat and down all the way inside the body.
    8. Fill the cavity with E6000 so it seeps around the edges to hold the entire sleeve. Use lots of glue.
    9. Put tape over the edges so the tape doesn’t spill over either edge.
    10. Put the wings on something that keeps them level, so the glue doesn’t flow downhill.
    11. For the main body, tape the sides of the sleeve and the insides so the glue doesn’t seep in.
    12. Make sure the main body is level while the glue cures.
    13. Add spar caps and glue with E6000.
  4. Thin spars:
    1. Lightly open the channels with a hacksaw blade, so it sits exactly on the surface.
    2. Cut the spars longer, so you can grip the end and spin it while gluing.
    3. Tape around the channel so glue doesn’t spill out over the channel.
    4. Put glue in, turn the spar around and remove excess.
    5. Take the tape off ten minutes after you apply the glue, so the tape doesn’t stick.
  5. Elevons:
    1. Mark the top and bottom on the balsa.
    2. Cut the balsa in some way.
    3. Hold both elevons together and sand them together to make them identical.
    4. Possibly sand the balsa where it meets the body, for full articulation.
    5. Mount the elevons with two pieces of tape stuck to each other, overlapping, so there are two sticky sides.
  6. Servos:
    1. Possibly use larger control horns, found on Thingiverse, because reasons.
  7. Winglets:
    1. Glue the winglets completely flush with the tip of the wing.


Make sure you use the tallest control horns possible and have loads of expo in for the roll axis (pitch is fine). Matt (because the MD is very roll sensitive as I found out to my surprise).

Last updated on November 27, 2020. For any questions/feedback, email me at

A simple guide to PID control

I made some changes to my quadcopter the other day for a new photography project I’m working on. Unfortunately, it turned out that it wasn’t good enough, and that I’d have to tune my PID loop, which I knew nothing about. After watching a few videos and reading a few things, I learnt enough to be dangerous, and to hopefully be able to explain the concepts simply, so I want to write them down here before I forget.

Basically, a PID loop can be thought of very simply as an equation that takes your current state as input and gives you what you need to do to reach a desired state as output. For example, if you had a radiator and wanted to heat a room, the PID loop would take the current temperature as input and tell you how high you needed to set the radiator on a 0-100% scale to achieve a desired temperature.

The PID loop has three components, and to tune it you need to set three weights that you multiply each parameter with. That means that it’s basically output = P*prop, + I*intgr + D*deriv, where the terms are explained below:

  • P - proportional: This is the weight of the difference between the current position and the desired position. What this says about the radiator is “we’re still far away, we need more heat!”, so the more P you set, the higher the radiator will be set for a given temperature difference.
  • D - derivative: Because P is purely based on the difference between the current and target temperatures, it doesn’t know anything about inertia. So, even though your radiator will be getting closer to the target temperature, even when it’s very close, P will be saying “more heat, we’re not there yet!”, and cause you to overshoot your target, having to then go back (possibly turning the AC on, undershooting downwards, and then back upwards, oscillating like that for a long time). D helps by saying “whoa, we’re getting there, slow down with the heat”, and reducing the amount of heat you apply proportionally to how fast you’re getting to your target temperature.
  • I - integral: I helps in the case where you left a window open in the room, and P is saying “okay we’re pretty close so set the radiator to 10% just for that final push”, but the room is leaking so that 10% will never get you to your target temperature. I helps by saying “Okay we’ve been trying but it’s not working, we’re still far, so we actually need a bit more heat than 10%”, by looking at the constant temperature difference you’ve been having lately, despite your best efforts. Basically, I deals with accumulated error when you think you’re getting closer but all you’re doing is fighting losses, so I allows you to close that gap.

That’s pretty much it!

Last updated on January 07, 2021. For any questions/feedback, email me at

E6000 hinges

I love Goop/E6000 glue, it’s very versatile and makes for a great bond. However, do remember to work with it outside, as it is not safe to breathe. One of the coolest things you can do with it is make hinges, for control surfaces as well as for any hatches you may have.

E6000 hinges are very strong (I tried tearing one by hand but couldn’t, in the end I had to cut it), and very flexible (you can easily turn the hinged surface 180 degrees up or down with very little force). They also have almost zero play, making them ideal for control surfaces.

Here’s how:

  • Make sure your surfaces are clean and straight. Since you’re going to make a hinge by placing a very thin layer of glue over the two pieces, the pieces need to actually be straight and contacting on the part where the glue is going to go. If there’s a recess or groove where your elevons meet, this won’t work very well because your glue layer will be too thick to bend properly.
  • Apply some masking tape parallel to the hinge line, 1 cm above and 1cm below it, so you don’t get glue elsewhere on the wing.
  • Place the elevon/aileron/other control surface in position and apply some masking tape to the two ends, to hold the elevon in place. Take care to position it straight on both axes, the control surface should be at the same level as the wing surface across its length and the control surface shouldn’t be deflected up or down.
  • Apply a thin layer of glue (around 1mm thin) on the top of the joint (not on both sides), and spread it evenly with a credit card or piece of paper.
  • Wait for it to dry, and you’re done!

Because a description might be hard to follow, you can see the process in more detail in this video.

Last updated on March 22, 2021. For any questions/feedback, email me at

FPV frequency chart

If you’re curious about which frequencies to use for video when there are multiple people flying FPV, as well as which bands are used by various manufacturers, here’s a handy chart:

FPV frequency chart

It was made by 5zero7 RC with information from a Propwashed article.

Best channel groups

Here are the best channel groups for each number of pilots, from the chart:

  • 2 pilots - E2 (5685), E6 (5905)
  • 3 pilots - E2 (5685), F4 (5800), E6(5905)
  • 4 pilots - E2 (5685), F2 (5760), F7 (5860) E6 (5905)
  • 5 pilots - E2 (5685), F2 (5760), F4 (5800), F7 (5860), E6 (5905)
  • IMD5C - R1 (5658), R2 (5695), F2 (5760), F4 (5800), E5 (5885)
  • 6 pilots - E2 (5685), F1 (5740), F3 (5780), F5 (5820), F7 (5860), E6 (5905)
  • IMD6C - R1 (5658), R2 (5695), F2 (5760), F4 (5800), F8 (5880), R8 (5917)

Last updated on January 09, 2021. For any questions/feedback, email me at

Getting uninverted SBUS on a no-name FrSky-compatible receiver

I got an RC receiver from Banggood. There’s uninverted SBUS on this pad:


To break this out to the SBUS pad, I had to remove/bridge the resistor that is circled in the image, and remove/bridge the FET on the other side:


Last updated on November 24, 2020. For any questions/feedback, email me at

Getting uninverted SBUS/SmartPort on the FrSky XSR receiver

To get uninverted SBUS/SmartPort on the FrSky XSR/X4RS receiver, you can repurpose the CPPM pad. Remove the two small resistors shown in the image, and solder the two lower pads (together) to either the CPPM pad or the MOSFET pin shown in the photo:


They should be soldered like this (remember to solder both resistor pads together):


Now the CPPM pad will be uninverted SBUS/SmartPort instead. It seems to be a bit of a gamble whether you get SBUS or SmartPort, it might be firmware-dependent. On firmware 2.1.0 FPort, I actually got the uninverted FPort signal on the CPPM pin, which is what I wanted.

Last updated on November 24, 2020. For any questions/feedback, email me at

INAV tuning tips

Here are some general INAV tuning tips and things I’ve learned throughout my builds. Keep in mind that these only apply to wings (and maybe planes), not quads:

  • To make turns in automatic modes smoother, use set nav_fw_control_smoothness = 8.
  • Pawel says that the idea of the software LPF is to replace the hardware LPF. Leave the hardware LPF set to 256 Hz and set the software LPF to 20-30 Hz, with a looptime of 1k.

Battery monitoring

To monitor how much battery you have left in flight, voltage isn’t a good indication because it can sag a lot. mAh is also not a good indication, because it doesn’t decrease linearly with voltage (when voltage drops, you need to consume more amps for the same amount of motor RPM, and thus thrust). Remaining energy (in Watt-hours) is a better way, using the “Wh drawn” INAV OSD item. In addition, INAV has heat loss compensation for the energy meter (done by simulating the internal resistance of the battery), which gives you a more accurate reading.

To calculate the Wh a battery can give, the best way is to charge or discharge it and see how many Wh were spent, if your charger shows you. Another way is to get a rough estimate using the formula no_cells * 3.7 * Ah. So, for a 1800 4S battery, the maximum Watt-hours are 4 * 3.7 * 1.8 = 26.64 Wh. You should not discharge more than 80% of that value, or you risk excessive wear to the battery.

For a 4S battery, I go with a rule of thumb: The maximum Wh is mAh / 85, so for a 5000 mAh battery I’ll land after 58 Wh consumed, which is around 80% of the battery consumed and gives a small margin for error.

More details can be found in the battery page in the INAV wiki.

(Thanks to Michel Pastor in the INAV Telegram group for this tip.)

Horizon drift issues

There’s a known problem with horizon drift on fixed wings. To ameliorate it, use set imu_acc_ignore_rate = 10. Setting this low is a good idea, but if it’s set too low then the accelerometer will effectively be ignored and the horizon will eventually drift. To reduce the accelerometer’s influence, you can also reduce imu_dcm_ki and/or imu_dcm_kp.

You can also try tuning fw_turn_assist_pitch_gain, although be careful to not set it too high because then the aircraft will stall trying to climb during a turn.

Adding a piece of black, porous foam (so wind can pass through) over the barometer has been known to help as well.

Last updated on January 01, 2021. For any questions/feedback, email me at


This is a bunch of miscellaneous info that wouldn’t fit anywhere else:

  • The ZOHD Dart 250g with the stock motor draws 4.5A on 2S with the 5x5 propeller. It draws the same amperage at exactly 75% throttle with a 3S battery and the same propeller.
  • When wiring your electronics, make sure you don’t have any ground loops. This means that there should only be one ground wire going to each component. For example, the ESC has one ground wire for power (to the battery) and one for signal (to the FC), you should only use one of the two (the one going to the battery). What you can do for the other ground wire, though, is twist it around the signal wire and only connect it to the FC side, to reduce emissions. If you have coaxial cable, you can do the same, connect the outer shielding to the FC’s ground, and don’t connect the other side anywhere, and use the core as signal.
  • If you want to embed knurled nuts in foam so you can use screws, use a soldering iron. Set the iron to 150 C, put the nut on the tip of the iron, and push the nut into the foam. It will slowly melt the foam and embed itself quite firmly. Don’t use a higher temperature or you’ll open a larger hole and the nut won’t fit snugly.
  • This is the command I used to flash an ESP8285 M3 with esp-link: --port /dev/ttyUSB0 --baud 115200 write_flash -fs 1MB -fm dout \
                    0x00000 boot_v1.7.bin 0x1000 user1.bin \
                    0xFC000 esp_init_data_default.bin 0xFE000 blank.bin
  • Propellers have a direction: The top usually has letters like, for example, “6040” (which denotes the size and pitch of the propeller), and the top needs to always point towards where the plane will be flying (the front). No matter if you have a pusher or puller, the top of the propeller needs to be pointing forward.
  • When it comes to cameras/standards, the difference between PAL and NTSC is that PAL has higher resolution (625 lines, ie 576i for PAL vs 525 lines, ie 480i for NTSC), but lower framerate (25 fps for PAL vs 29.97 fps for NTSC). I use PAL because I prefer having higher resolution.
  • If doing manual/hand launches of planes/wings, you’ll notice that you need to have your hand on the pitch/roll stick when launching, which means you need to launch with your left hand, which is where the arm and throttle controls usually are. That makes it hard to throttle up to start the launch, or down (or disarm) in an emergency.
    To make things a bit easier, I set the back right switch (SG) to override the throttle and set it to the launch throttle (40% for me, for example). That way, I can arm, keep the throttle down, and flip SG with my right hand. That will throttle up enough to easily launch the wing, and if something goes wrong I can still either disarm or flip SG down so the motor stops again.
  • ESCs that run on the DShot protocol don’t need throttle calibration, you can go ahead and use them right away and they’ll do the right thing.

Motor and prop stuff

Here are the things I know about motors and propellers:

  • The larger and steeper the propeller, the harder it is for the motor to turn.
  • The more KV the motor is, the faster it turns, and the harder it is for it to turn.
  • The harder the motor has to turn, the more current it draws, and the hotter it gets.
  • The larger the (physical) size of the motor, the more heat it can dissipate.
  • The more amps (current) the motor draws, the hotter it gets (proportional to the square of the current).
  • If the motor gets too hot, some part of it may melt. This ruins the motor.
  • The smaller a propeller, the more quickly it can turn, and the more it can accelerate.
  • The larger a propeller, the more efficient it is.

Last updated on November 22, 2021. For any questions/feedback, email me at

Omnibus F4 pro servo diode

To isolate the servo 5V rail from the controller’s 5V power supply, remove this diode:


Now the servos’ 5V rail can be powered from another 5V supply to avoid servo current backflow into the FC.

There’s also a schematic for this FC.

Last updated on April 09, 2021. For any questions/feedback, email me at

Omnibus F4 V3 pinout

This is the pinout of the Omnibus F4 V3:




Last updated on January 06, 2021. For any questions/feedback, email me at

QGroundControl to Mission Planner conversion script

If you have a parameter dump from QGroundControl, I wrote a small script that will convert it to a Mission Planner compatible file. You can also use Parachute to do your backups/restores/conversions.

Just save this script somewhere as convert_qgc_params and run it as ./convert_qgc_params <qgc params> <output file>:

#!/usr/bin/env python3
import sys
from decimal import Decimal

def format_float(f):
    return "{0:f}".format(Decimal(f).quantize(Decimal("1.0000000")).normalize())

def main(infile, outfile):
    with open(infile) as ins:
        inputs =

    lines = []
    for line in inputs.split("\n"):
        if not line or line.startswith("#"):
        vehicle_id, component_id, name, value, type = line.split("\t")
        v = value
        if type == "9":
            v = format_float(float(value))

    with open(outfile, "wt") as outs:

if __name__ == "__main__":
    main(sys.argv[1], sys.argv[2])

Last updated on March 04, 2021. For any questions/feedback, email me at

Transmitter external module pinout

The transmitter (Taranis, Jumper, RadioMaster, etc) pinout is, from top to bottom:

  • PPM
  • +6V
  • +BAT
  • GND
  • ANT

It’s illustrated in this photo:


Last updated on November 24, 2020. For any questions/feedback, email me at

Transportable C1 Chaser

I have a C1 Chaser, and it’s a fantastic wing. It flies great, and is very efficient. The only problem I had with it was that it’s too long to easily carry around, as it has a 1.2m wingspan.

I thought that a C1 Chaser that can break apart for easy transport would be the ideal long-range wing, so I bought a second one and made some modifications to it. I’m listing the modifications here so you can do the same if you want to.


The biggest issue is making the spar removable. The best way I’ve found to do that is to use IKEA drinking straws, they have an internal diameter of around 7.5mm, making them ideal for putting the spar through. If you find the spar has too much jiggle, I’ve found that applying some CA glue around it makes it thick enough to fit snugly in the straw.

I’ve cut three straws to length, sanded the straws and the spar channel a little with coarse sandpaper, and glued the former in the latter, as you can see here (the straw in the photo is not cut to length yet):

Make sure to leave a few mm from the inside edge of the wing (so the straw doesn’t touch the edge, again not pictured in the photo), so the spar’s edge doesn’t rub against the straw, to avoid splitting it. Also, leave the spar in the straws while gluing, so the straws don’t lose their shape (but make sure you don’t get glue on the spar and end up gluing it to the straw).

For glue, I use E6000 (sold as Goop in the US) for pretty much everything, but for this one you can use your favorite glue that you know won’t dissolve EPO.

This is what the final result will look like:


Connecting the wings has two problems:

First, you need the wing to be stable against rotation around the spar. Already, the notch the C1 has stops the wing from rotating up, but it does not stop it from rotating down (since you’re meant to glue it in place).

Second, you obviously need the wing to be stable against left/right motion, or it will slide off the spar. To solve these problems, I designed a simple connector with two halves, one of which goes onto the fuselage and one onto the wing:

The connector has two components, one is a cylindrical channel for a carbon tube (which you can glue to one of the pieces, as in the photo) that stops the wing from rotating around the spar, and the other is a channel for an o-ring, which keeps the two halves from moving left to right.

I used a 6mm outer diameter carbon tube and an o-ring with an inner diameter of 28mm and a cross-section diameter of 3.5mm. A slightly thicker and slightly longer o-ring will also probably work.

To install, place the connector over the underside of the wing and mark the outline, then cut the foam and glue the connector in. Do the same with the other side, into the fuselage, as shown in the photo below. To make sure the connectors are glued straight, I recommend cutting the foam to shape, placing the connectors in on both sides, and sliding them into each other (using the tube), making sure to leave some distance and watch for any places where glue has leaked, to prevent the wing and the fuselage from gluing together. Also, make sure to not use glue the part of the connector that’s not going to be next to foam, on the fuselage side, to prevent the wing tab from adhering when you slide them together (watch out for glue seeping from under the connector towards the tab).

This is the end result:

To mount the wings, just insert the spar into the fuselage, insert the wings (making sure both tubes go into their respective holes), and place the o-ring into both halves of the connector. That gives you a secure and quick assembly.

Vertical stabilizers

The last part is securing the vertical stabilizers. I did this with two very small 3D-printed pieces, I slot the stabilizers horizontally (on the left/right axis) onto the fuselage and then connect the wings, which keeps the stabilizers securely in place.

First, press the stabilizer-side part (the Π-shaped one) onto the stabilizer on the place where you want it (I put it as shown in the photo), and cut slightly inside the indentation it creates. Then, glue it into place:

Then, insert the fuselage-side part (the inverted-T-shaped one) into the stabilizer-side part, align the stabilizer with the fuselage and press it in, to create the indentation onto the fuselage EPO, so you know where to cut. Insert the part into the cut and glue it in:

When everything has set, you can install the stabilizers by simply slotting the two parts into each other and mounting the wing. That way, the stabilizer isn’t going anywhere, and you can install and remove it very quickly.

The end

You’re done! Enjoy your disassemblable, transportable C1 Chaser!

Last updated on February 03, 2021. For any questions/feedback, email me at


Click on a link in the list below to go to that page:

  1. Battery discharge curves
  2. Electronics tips
  3. GRBL_ESP32 tips
  4. How to properly level your 3D printer

Battery discharge curves

I wanted to buy some Sony VTC6 batteries, and I was wary of fakes, so I wrote a battery discharge calculator with an associated hardware component (just a simple current and voltage sensor). I then took some measurements of my known-good batteries, and the new ones I bought.

The methodology was the following: I connected the battery to the sensor, and the sensor to a configurable load. I set the load to draw a certain amount of amps until it reached a cutoff voltage, and then to stop. I then plotted mAh drawn versus voltage, as well as amps drawn.

The batteries I connected were in various states of use, and various configurations (for various reasons, I couldn’t test single cells). The configuration, state of the battery and provenance are mentioned below.

Here are the graphs:

Genuine Sony VTC6

This is a genuine (as far as I can tell) Sony VTC6, fairly used in high amp draw situations (I use it in my plane), in a 3S configuration:


You can see that it output around 2600 mAh before I stopped it at 3V, which is quite good.

Here’s a brand new genuine VTC6, again in a 3S configuration:


This time I ran it all the way down to 2.8, and you can see it output the full 3000 mAh.

Fake Sony VTC6

This is a pretty blatantly fake “Sony VTC6”, brand new, in a 2S configuration:


The performance falls off a cliff after around 3.6V, and it only outputs 1600 mAh before it dies completely.

Trying to draw 6-7A is even more spectacular (and it gets very hot to the touch):


Notice the huge voltage sag right as the load starts drawing.

White CNHL 4S 4000 mAh

This is a white CNHL 4S 4000 mAh LiPo battery, slightly used:


You can see that it’s pretty decent, outputting nearly all of its nominal mAh, decently linearly, with a slightly faster drop after 3.7 V.

Last updated on September 12, 2021. For any questions/feedback, email me at

Electronics tips

This page contains various notes and tips about electronics.

Decoupling capacitors

StackOverflow has a good answer on why use decoupling capacitors in the context of a stepper driver:

There are two purposes of such capacitor:

  • first it supply power for short peaks in demand, so effectively enabling the 12V power source supply much more current for short time, than it can support over long time and so the driver have more stable power and works generally better. Also it protects the driver from noise of other parts.
  • the other is protect all other parts from voltage drops and noise caused by the driver. It is recomended to have capacitors as near as possible to any IC/driven circuit for this reason.

So basically - if you have good power source, you can often get away even without such capacitors. But if you power also logic from the same source, it is already better to have some capacitors on power lines where posssible. Escpecially if you expect some noise around (like having motors near or lines to motors in paralel with other lines ...). Depends how much you care and how critical you see the project. Hobby project just for fun can go even without capacitors and be all good. Good industry projects have capacitors always everywhere.

I had project, where it worked even without capacitors (laser printer), but now I would place some there in any case near each driver, just to be sure. 100uF is really good capacity, enables for lot power. But if you use any other value (which you have more ready), it should not hurt too. It is not about if it would work or not, it is more about if it ensures, that it would work flawlessly even in bad conditions even under unexpected conditions and would not have “sometimes strange problems, which disapear spontaneously during debugging”.

Also note, that for improving power are good high capacity electrolytes. For preventing noise are much better ceramic (which are fast, even if they have a lot smaler capacity) and so many people put both there (like 100uF electrolyte and 100nF ceramic in paralel).

Short answer: Do as you want, it would probably work anyway. I personally would place big+small capacitors near each driver.

LDO recommendation

Asking for a recommendation for a good 3.3V LDO, someone said:

There’s a number of good parts. In the 500mA range I’d highly recommend the Holtek HT7833. If you need closer to an amp at 3.3, the Torex XC6220 is popular, but I haven’t used that one myself. Another popular part I haven’t used is the Diodes Inc. AP2112, 600mA. The Holtek has 4uA quiescent current, the other two are around 50uA. has all three parts.

Driving a relay

David Albert said:

When energizing a relay, you are charging a coil (inductor). To turn the relay on, you can use an NPN transistor (e.g. 2N3904) with the collector to the coil and the emitter to ground. The other side of the relay coil will go to +5V. You will need a resistor (try 1K) between your transistor base and your 3.3v control source. You will also need a diode in parallel with the coil: cathode towards +5V, anode at the junction of the transistor collector and coil. The purpose of the diode is to prevent your transistor from being destroyed when you turn off power to the coil. When you remove power from a coil, the energy stored in the coil (as a magnetic field) collapses back into the coil inducing a current flow in the coil. The voltage will climb until the current can flow (e.g. by destroying your transistor). The reverse-biased diode gives the current a path to flow so nothing gets damaged. Also, make sure your transistor is rated to carry the current needed to energize your coil (e.g. a 2N3904 is rated to deliver at most 200mA; if you need more than that, choose a transistor with a larger current rating).

The resistor between the control source (e.g. an ESP32 GPIO pin) and the base of the transistor is to limit current. Whatever goes into the base will flow directly through to the emitter (to ground)...the resistor limits that current. When current is flowing through the base-emitter junction, a much larger current will flow through the collector-emitter junction (energizing the relay coil).

There is more info on StackOverflow: Selecting a switching transistor for a 5V relay

Last updated on December 13, 2020. For any questions/feedback, email me at

GRBL_ESP32 tips

I made a CNC that uses a custom board I designed, and which runs GRBL_ESP32. I couldn’t find the following info easily, so I’ve written it here:

  • You can specify the enable pin for the drivers with the STEPPERS_DISABLE_PIN option. This should be used like #define STEPPERS_DISABLE_PIN GPIO_NUM_2.
  • To invert the enable signal, you can use #define DEFAULT_INVERT_ST_ENABLE 1. My board needed the enable signal to not be inverted (that’s what A4988/Trinamic TMC2208 drivers need), so I set it to 0.
  • To always keep the steppers enabled (locked) to avoid them moving, you can specify $Stepper/IdleTime=255. That’s the maximum timeout and will always keep them enabled.

Last updated on February 15, 2021. For any questions/feedback, email me at

How to properly level your 3D printer

I see many people on our 3D printer Facebook group ask about adhesion issues with their printer. 99% of the time, this is because they have leveled improperly, and not because of the bed material.

I have taken photos of filament when the nozzle was leveled at various heights from the bed. I greatly recommend an adjustable Z endstop, which will save you lots of time when leveling/tramming.

In this first photo, I have leveled too high (meaning the nozzle is too high compared to the bed). You can see that the filament is cylindrical, which means that it has just dropped onto the bed (or minimally touched it), leading to very poor adhesion. You can imagine that, if the filament is just dropped onto the bed, it won’t adhere well:


The next photo is also a bit too high. It’s not as high as the previous photo, so it has partially adhered, but there are gaps between the rows and adhesion still won’t be great:


The next photo has been leveled too low. The filament is mushed against the bed, but it’s mushed too much, leading to transparent-looking rows of filament. The specific filament I’m using tends to look transparent even when leveled properly, but this is too low regardless:


For the last photo, I’ve leveled it pretty much perfectly. You can see that the rows aren’t cylindrical at all, instead they’re long strips that are touching each other properly and don’t look too transparent. If you insert a piece of paper between the bed and the nozzle, you will be able to move it with some difficulty, but it won’t move very freely.


There you have it! If your filament looks cylindrical, follow your printer’s manual to reduce the distance between bed and nozzle. If it looks transparent and missing in places completely, you need to increase the distance. If it looks mushed and has the proper color, and the rows are touching each other just so, you’re perfect and ready to print!

I hope this guide has helped you, feel free to share it with your friends.

Last updated on November 20, 2020. For any questions/feedback, email me at


Click on a link in the list below to go to that page:

  1. Black pills
  2. Monero GUI syncing stuck with Ledger
  3. Test and format SD cards

Black pills

I’ve been trying to flash these Black Pills I have (STM32F401), the official STM32 flasher worked great, STM32CubeProgrammer.

Run with:

./ -c port=USB1 -d firmware.bin 0x08000000

dfu-util also worked, eventually, after an unspecified amount of messing around with udev rules (if it doesn’t work for you out of the box, try the rs-probe udev rules).


This finally worked

Clone the repo: and cd examples.

cargo objcopy --release --example delay-timer-blinky --features="stm32f401,rt" -- -O binary out.bin

dfu-util -a 0 --dfuse-address 0x08000000 -D out.bin

Last updated on December 30, 2021. For any questions/feedback, email me at

Monero GUI syncing stuck with Ledger

This is about the Monero desktop GUI, but probably also applies to Monerujo.

If you’re trying to sync the blockchain with your Ledger device, you might be getting the conflicting messages of “Waiting for daemon to sync” and “Daemon is synchronized”, which then just stays there forever and doesn’t move.

You may see something like this in the log:

ERROR	wallet.wallet2	src/wallet/wallet2.cpp:3449	Error parsing blocks: Unable to send hidapi command. Error 128: Unknown error
ERROR	wallet.wallet2	src/wallet/wallet2.cpp:3512	pull_blocks failed, try_count=3

These errors are caused by the Ledger not being connected. You need to leave the Ledger connected throughout the syncing, as apparently the node needs some info from it and won’t notify you if it’s not there. It also doesn’t seem to work if you disconnect and then connect the wallet afterwards.

Letting the Ledger go to the screen saver or lock appears safe, at least with the Nano X I tried. Just leave it connected, and it’ll sync fine.

I’ve opened a suggestion on the Monero issue tracker to improve the UX of the Ledger integration in general.

Last updated on January 04, 2021. For any questions/feedback, email me at

Test and format SD cards

I wrote a short bash script that tests SD cards with F3 to see if they’re fake, deletes everything on them, creates a new partition table and one exFAT partition on them.

Here it is:

#!/usr/bin/env bash

set -euox pipefail

sudo umount --force "$1"1 || true
sudo f3probe --destructive --time-ops "$1"
sudo parted --script "$1" "mklabel msdos" "mkpart primary ext4 0% 100%"
sleep 1
sudo mkfs.exfat -n Stavros "$1"1
eject "$1"

Save it as and run it as ./ /dev/sdX.

Last updated on August 18, 2021. For any questions/feedback, email me at