All Drone Lab posts

Guides

Gorilla Whoop Whoop Guide: Setting Up a BetaFPV Air75 on Linux

September 13, 20268 min read

This guide gets a BetaFPV Air75 flashed with Betaflight 2026.6.2 and flying, from a Linux machine. I used Arch, but everything except the package commands works on any distro.

It's the guide I wish I'd had. I made every mistake in it at least once, so you don't have to. The short version of what goes wrong:

  • Linux won't let the browser talk to the drone until you fix USB permissions.
  • There are three revisions of the Air75's flight controller with the same name. Pick the wrong one and half your motors stop working.
  • A fresh flash erases everything, and several settings the Air75 needs aren't defaults.

The story behind all of this is in Episodes 0 and 1. This post is just the steps.

What you need

ItemNotes
BetaFPV Air75Analog version, built-in ExpressLRS receiver
USB adapterComes in the box with the Air75
1S batteryMotors and video transmitter don't power up on USB alone
ExpressLRS radioI use a RadioMaster Pocket (EdgeTX)
Chromium-based browserChrome, Chromium, Brave or Edge. Firefox can't do WebSerial or WebUSB
Betaflight Appapp.betaflight.com, runs in the browser
Linux with sudo accessArch here; adapt pacman commands for your distro

Optional: base-devel and git if you want to compile the firmware yourself. You don't have to.

Step 1: Fix Linux USB permissions

The drone shows up two ways over USB. In normal mode it's a serial port (/dev/ttyACM0). In flashing mode, called DFU, it's a raw USB device. Linux blocks regular users from both by default.

Run this once:

# serial port access (Arch uses the uucp group; Debian/Ubuntu use dialout)
sudo usermod -aG uucp $USER

# let regular users flash the STM32 in DFU mode
echo 'SUBSYSTEM=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="df11", MODE="0664", GROUP="uucp"' | sudo tee /etc/udev/rules.d/45-stdfu.rules
sudo udevadm control --reload-rules

Then log out and back in so the group change takes effect. Skipping this is the number one reason flashing hangs forever with no error.

Step 2: Back up before you touch anything

Flashing wipes every setting on the flight controller. Save them first:

  1. Plug in the Air75 over USB and click Connect in the Betaflight App.
  2. Open the CLI tab, type diff all, and press Enter.
  3. Copy everything it prints into a text file, like air75-backup.txt.

The most useful line is board_name near the top. It tells you which firmware target the drone shipped with. Write it down for Step 3.

Step 3: Identify your board revision

This is the step that cost me a whole evening. Betaflight has three targets for this flight controller: BETAFPVG473, BETAFPVG473_V2 and BETAFPVG473_V3. They share a processor but wire the gyro, motors and battery sensor to different pins. Flash the wrong one and something important quietly stops working.

The pin maps, from the Betaflight config files:

TargetGyro CS / interruptMotor 3Motor 4Battery voltageSymptom if wrong
BETAFPVG473 (V1)PA4 / PC4PB6PC13PA0GYRO: None, board won't arm
BETAFPVG473_V2PC14 / PC15PC6PA4PA0(mine: everything works)
BETAFPVG473_V3PC14 / PC15PB6PB9PA4Gyro fine, motors 3 and 4 dead, wrong battery reading

How to tell which one you have:

  1. Best: the board_name from your Step 2 backup. Build that exact target.
  2. No backup? Look at the gyro chip on the board. Mine reads BMI270, which V2 supports.
  3. Already flashed something? In the CLI, run status. If GYRO: says None, the gyro pins are wrong. Then run resource and test motors. If motors 3 and 4 are dead, you're on V3 and need V2, or the other way round.

My Air75 turned out to be V2. Yours may not be. Check before you flash.

Step 4: Get the firmware

Use a stable release. I used 2026.6.2. Don't build from the master branch: that's the development version, and the regular Betaflight App will warn that it doesn't support it.

Option A: let the app build it (recommended)

In the Betaflight App, disconnect, then open Firmware Flasher:

  • Board: pick your target by hand, e.g. BETAFPVG473_V2. Don't trust auto-detect here.
  • Version: 2026.6.2
  • Radio protocol: CRSF · Telemetry: CRSF · OSD: Analog (MAX7456) · Motor protocol: DSHOT
  • Click Load Firmware [Online].

This always includes the board config, so you can't end up with an unconfigured board.

Option B: compile it yourself

For the curious, or people who distrust buttons:

sudo pacman -S --needed base-devel git python
mkdir -p ~/src && cd ~/src
git clone https://github.com/betaflight/betaflight.git
cd betaflight
make arm_sdk_install      # downloads the exact ARM compiler; run inside the repo
git fetch --tags
git checkout 2026.6.2     # stable release, not master
make configs              # downloads board definitions
make clean
make BETAFPVG473_V2       # your target from Step 3
ls obj/*.hex

If you see No rule to make target 'arm_sdk_install', you're not in the betaflight folder. If git checkout mentions "detached HEAD," that's normal. It just means you're on a release instead of a branch.

Step 5: Flash it

The app is supposed to reboot the drone into flashing mode (DFU) by itself. On my setup it didn't, and the flash sat there waiting forever. Doing it by hand works every time:

  1. Connect, open the CLI, type bl and press Enter. The drone disconnects. That's expected.
  2. Check that Linux sees it in DFU mode:
    lsusb | grep 0483

    You want 0483:df11 ... DFU Mode. If it says 0483:5740, it's still in normal mode; repeat step 1.

  3. In Firmware Flasher (only visible while disconnected), turn on No reboot sequence.
  4. Load the firmware: [Online] from Step 4 Option A, or [Local] and pick your .hex from ~/src/betaflight/obj/.
  5. Click Flash Firmware. When the browser asks for a device, pick STM32 BOOTLOADER.
  6. Wait for Programming: SUCCESSFUL, usually under a minute.

If the device picker is empty, go back to Step 1. In Brave, also try turning off Shields for the site. An interrupted flash won't brick the board. Just put it back in DFU and flash again.

Step 6: Restore and configure

First, confirm the right firmware landed. Connect, open the CLI and run status. You want CONFIG: CONFIGURED, a gyro listed (mine: BMI270), and OSD: MAX7456. On V2, resource should show MOTOR 3 C06 and MOTOR 4 A04.

Restore your backup, carefully

Open your Step 2 backup in a text editor and delete these lines before pasting it into the CLI:

  • board_name, manufacturer_id, mcu_id, signature
  • any resource and timer lines, which belong to the old target
  • acc_calibration, so you can recalibrate fresh
  • anything the CLI marked ###ERROR IN diff: CORRUPTED CONFIG###
  • align_board_yaw, unless you set it on purpose

Paste the rest, then type save.

Settings the Air75 needs

If you're starting fresh, here's the minimum. Paste into the CLI:

serial UART2 2048 115200 57600 0 115200
set yaw_motors_reversed = ON
save

What that does, and what to set in the app:

WhereSettingWhy
PortsUART2 Peripherals = VTX (SmartAudio)Lets Betaflight control the video transmitter
PortsUART3 Serial RX = onThe built-in ExpressLRS receiver
ReceiverSerial (via UART), provider CRSFHow ExpressLRS talks to Betaflight
MotorsMotor direction reversed = onThe Air75 flies props-out
SetupCalibrate Accelerometer, drone flatRequired after every flash
ModesARM on a 2-position switch, ANGLE/HORIZON on a 3-position switchDon't put ARM on a momentary button
Video TransmitterBand, channel, power, then SaveBattery must be plugged in for the VTX to respond

Two gotchas:

  • The VTX table. The stock one has power levels 1/2/3/4 = 25/100/200/400 mW. Level 4 is 400 mW, not 200.
  • ExpressLRS VTX Administrator. If you set VTX options in the radio's ExpressLRS menu, the radio pushes them to the drone every time it connects and silently undoes your Betaflight changes. Set its Band to Off, or make it match. Pick one boss.

Also, in the US, analog FPV at these power levels generally needs a ham radio license. Some Raceband channels sit outside the license-free 5.8 GHz band.

Step 7: Pre-flight checks, props off

Do all of these with the props removed and a battery plugged in. I found a reversed throttle this way. Full power at "zero throttle" is a much better discovery without props.

  • ☐ Receiver tab: throttle stick down reads about 1000, up about 2000. Roll, pitch and yaw move the right way. If one is backwards, fix it on the radio (EdgeTX: MDL → OUTPUTS → that channel → Direction).
  • ☐ Modes tab: the ARM marker sits inside the range only when the switch is in your armed position.
  • ☐ Motors tab: all four spin, in the right corner (1 rear right, 2 front right, 3 rear left, 4 front left) and the direction the diagram shows.
  • ☐ Arm test: unplug USB, throttle down, arm. Motors idle slowly and speed up with throttle.
  • ☐ Failsafe test: while armed, switch the radio off. Motors must stop within a second or two.
  • ☐ Battery reading: a charged 1S pack reads about 4.2 to 4.35 V.
  • ☐ Props on, each matched to its motor's spin direction.

First flight: ANGLE mode, open room, gentle throttle, finger on the arm switch.

Troubleshooting

SymptomCauseFix
No rule to make target 'arm_sdk_install'Not in the repo foldercd ~/src/betaflight first
App warns it doesn't support the firmwareDevelopment build from masterBuild a stable release tag
Flash hangs waiting for the deviceDrone never entered DFU, or no USB permissionCLI bl, check lsusb for df11, redo Step 1
CONFIG: UNCONFIGURED, GYRO: NoneGeneric or wrong-target firmwareFlash the board-specific target (Step 3)
Motors 3 and 4 don't spinV3 firmware on a V2 boardFlash BETAFPVG473_V2
No motors spin in the Motors tabNo battery, or safety toggle offPlug in a battery; turn on "I understand the risks"
All motors spin backwardsProps-out setting lost in the flashset yaw_motors_reversed = ON
VTX tab: "not configured or not supported"No battery, or UART2 not set to SmartAudioBattery in; Ports → UART2 → VTX (SmartAudio)
VTX settings revert after unpluggingRadio's ExpressLRS VTX AdministratorSet its Band to Off, or match it
Receiver tab shows no movementWrong receiver mode, or not boundSerial (via UART) + CRSF; check the receiver LED is solid
Won't arm, only CLI and MSP flagsARM range doesn't match the switchMove the range to where the switch actually sits
Full power at zero throttleThrottle channel reversed on the radioFlip CH3 direction on the radio; never arm with props on until fixed
Bounces on the ground at idleAir mode fighting the floorLower dshot_idle_value a little; disarm on landing
Video full of static5 GHz Wi-Fi on your channelMove channels; I found one that works for me

Sources