Arduino for Aerospace

Build real
hardware.

Arduino bridges aerospace theory to the physical world. Build barometric altimeters, IMU attitude systems, PID stabilisers, and rocket flight data loggers. Every project on this page includes complete wiring guides, full working code, and real serial output.

How Arduino works —
plain English.

Arduino is not complicated. It is a small computer with no operating system that runs one program in an infinite loop. Understanding three things gets you 90% of the way there.

The Structure

setup() and loop() — two functions, that's it

Every Arduino sketch has exactly two mandatory functions:

setup() — runs once when the board powers on. Use it to configure pins, initialise sensors, and start serial communication.

loop() — runs forever, repeatedly, as fast as the processor allows. This is where you read sensors, make decisions, write outputs, and send data. There is no operating system scheduling tasks — your code IS the operating system.

The language is C++, but a simplified subset. You do not need to be a software engineer to use it. The examples on this page are everything you need to start building real aerospace measurement systems.

The Pins

Three types of pins, three types of signals

The Arduino Uno/Nano has three categories of pins:

TypePinsWhat it does
DigitalD0 – D13HIGH (5V) or LOW (0V). LEDs, buttons, on/off signals
PWM~3,5,6,9,10,11Simulated analogue 0–255. Servo motors, motor speed
AnalogueA0 – A50–5V → 0–1023 (10-bit ADC). Pressure sensors, potentiometers
I²CA4(SDA), A5(SCL)Two-wire bus. BMP280 barometer, MPU-6050 IMU, OLED displays
SPID10–D13Fast four-wire bus. SD card modules, radio transceivers
UARTD0(RX), D1(TX)Serial comms. GPS modules, radio modems, PC connection
The Key Functions

Ten functions that cover everything

pinMode(pin, mode) — set INPUT or OUTPUT. Always call in setup().
digitalWrite(pin, val) — write HIGH or LOW to a digital pin.
digitalRead(pin) — read HIGH or LOW from a digital pin (button, switch).
analogRead(pin) — read 0–1023 from an analogue pin (sensor voltage).
analogWrite(pin, val) — PWM output 0–255 (only works on ~ pins).
delay(ms) — pause for ms milliseconds. Blocks everything else.
millis() — returns time in ms since power-on. Use instead of delay() for non-blocking timing.
Serial.begin(baud) — open serial port (9600 or 115200).
Serial.println(val) — print a value followed by newline.
Serial.print(val) — print a value with no newline (use for CSV rows).

Communication Protocols

I²C vs SPI vs Serial — which do you use?

I²C (two wires: SDA + SCL) — most modern sensors use this. Multiple sensors share the same two wires, distinguished by a unique address. BMP280 address: 0x76 or 0x77. MPU-6050: 0x68 or 0x69. Requires Wire.h.

SPI (four wires: MOSI, MISO, SCK, CS) — faster than I²C, used for SD cards, high-speed ADCs, radio modules. Each device needs its own CS (chip select) pin. Requires SPI.h.

Serial/UART (two wires: TX, RX) — used for GPS modules, radios, and communication with the PC. GPS sends NMEA sentences at 9600 baud. Always cross TX to RX and RX to TX between devices.

For most aerospace sensor projects: everything is I²C. For data logging to SD card: I²C for sensors, SPI for SD.

Six aerospace projects,
full working code.

Every project below is complete, ready-to-upload Arduino code for a real aerospace measurement or control task. Each includes exact wiring connections and expected serial output.

Reading an Analogue Sensor

Most physical sensors output a voltage proportional to what they measure. analogRead() converts that voltage (0–5V) into a number (0–1023) using the Arduino's 10-bit ADC. This pattern is the foundation for pressure sensors, temperature sensors, and pitot tube interfaces. This example reads a differential pressure sensor and converts to airspeed.

Wiring — MPXV7002DP Pressure Sensor VCC → 5V  |  GND → GND  |  Vout → A0
Sensor outputs 2.5V at zero differential pressure. Sensitivity: 1V/kPa.
ARDUINO C++ — pressure_sensor.ino
// ANALOGUE PRESSURE SENSOR → AIRSPEED CALCULATION // Reads MPXV7002DP differential pressure sensor on A0 // Converts voltage → pressure (Pa) → airspeed (m/s) const int SENSOR_PIN = A0; const float V_REF = 5.0; // Arduino supply voltage const int ADC_MAX = 1023; // 10-bit ADC maximum const float RHO_SL = 1.225; // air density at sea level (kg/m³) void setup() { Serial.begin(115200); // faster baud rate for continuous data Serial.println("Time_ms,Raw_ADC,Voltage_V,Pressure_Pa,Airspeed_ms"); } void loop() { // Step 1: read the raw ADC value (0–1023) int raw = analogRead(SENSOR_PIN); // Step 2: convert ADC to voltage // voltage = raw * (Vref / ADC_MAX) float voltage = raw * (V_REF / ADC_MAX); // Step 3: convert voltage to differential pressure (Pa) // MPXV7002DP: output = 2.5V at 0 Pa, sensitivity = 1V per kPa // pressure = (voltage - 2.5) * 1000 float pressure = (voltage - 2.5f) * 1000.0f; // Step 4: airspeed from dynamic pressure: V = sqrt(2 * dP / rho) float airspeed = 0.0f; if (pressure > 0.5f) { // only calculate if above noise floor airspeed = sqrt(2.0f * pressure / RHO_SL); } // Step 5: print as CSV — readable by MATLAB, Excel, Python Serial.print(millis()); Serial.print(","); Serial.print(raw); Serial.print(","); Serial.print(voltage, 3); Serial.print(","); Serial.print(pressure, 1); Serial.print(","); Serial.println(airspeed, 2); delay(100); // 10 Hz — good for airspeed measurement }
>> Serial Monitor (115200 baud)Time_ms,Raw_ADC,Voltage_V,Pressure_Pa,Airspeed_ms 102,512,2.500,0.0,0.00 205,539,2.631,131.0,14.62 308,573,2.799,299.0,22.09 411,544,2.646,146.0,15.44

BMP280 Barometric Altimeter

The BMP280 is a barometric pressure and temperature sensor communicating over I²C. Combined with the ISA barometric altitude formula, it gives altitude to ±1–2 m resolution — exactly how model rocket altimeters and UAV autopilots measure altitude for hold control. Install the Adafruit BMP280 library via the Arduino IDE Library Manager first.

Wiring — BMP280 to Arduino Uno VCC → 3.3V (NOT 5V — you will destroy the sensor at 5V)
GND → GND  |  SDA → A4  |  SCL → A5
I²C address: 0x76 (SDO pin low) or 0x77 (SDO pin high)
ARDUINO C++ — bmp280_altimeter.ino
// BMP280 BAROMETRIC ALTIMETER // Library: Adafruit BMP280 — install via Library Manager (Sketch → Include Library) #include <Wire.h> #include <Adafruit_BMP280.h> Adafruit_BMP280 bmp; float groundPressure = 0.0f; // calibrated at ground level void setup() { Serial.begin(115200); // Initialise BMP280 at I²C address 0x76 if (!bmp.begin(0x76)) { Serial.println("ERROR: BMP280 not found! Check wiring and I2C address."); while (1); // halt — do not proceed with bad sensor } // Configure for maximum resolution (slowest, but most accurate) bmp.setSampling( Adafruit_BMP280::MODE_NORMAL, // continuous measurement Adafruit_BMP280::SAMPLING_X16, // temperature: 16× oversampling Adafruit_BMP280::SAMPLING_X16, // pressure: 16× oversampling Adafruit_BMP280::FILTER_X16, // IIR filter: smooths noise Adafruit_BMP280::STANDBY_MS_1 // 1ms standby between measurements ); // Calibrate ground pressure — average 50 readings over 1 second Serial.print("Calibrating ground pressure"); float sum = 0.0f; for (int i = 0; i < 50; i++) { sum += bmp.readPressure(); Serial.print("."); delay(20); } groundPressure = sum / 50.0f; Serial.print(" done! P0 = "); Serial.print(groundPressure, 1); Serial.println(" Pa"); Serial.println("Time_ms,Pressure_Pa,Temp_C,Alt_AGL_m"); } void loop() { float P = bmp.readPressure(); // Pascals float T = bmp.readTemperature(); // Celsius // ISA barometric altitude formula: // h = (T0/L) * [1 - (P/P0)^(R*L/g)] // where T0=288.15K, L=0.0065K/m, R=287.058 J/kgK, g=9.80665 m/s² const float T0=288.15f, L=0.0065f, R=287.058f, g=9.80665f; float exponent = R * L / g; // = 0.1903 float alt_AGL = (T0/L) * (1.0f - pow(P/groundPressure, exponent)); // Print CSV row Serial.print(millis()); Serial.print(","); Serial.print(P, 1); Serial.print(","); Serial.print(T, 2); Serial.print(","); Serial.println(alt_AGL, 2); delay(100); // 10 Hz sampling rate }
>> Serial Monitor (115200 baud)Calibrating ground pressure.......... done! P0 = 101234.5 Pa Time_ms,Pressure_Pa,Temp_C,Alt_AGL_m 1250,101234.5,22.14,0.00 1351,101234.5,22.14,0.00 1452,101228.3,22.15,0.52 ← sensor raised ~0.5 m 1553,101207.1,22.16,2.26 ← sensor raised ~2.3 m

MPU-6050 IMU — Pitch & Roll with Complementary Filter

The MPU-6050 has a 3-axis accelerometer and 3-axis gyroscope on one chip. The gyroscope gives accurate short-term angle changes but drifts over time. The accelerometer gives true tilt angle from gravity but is noisy. A complementary filter fuses both: 98% gyroscope (fast, accurate, no drift short-term) + 2% accelerometer (corrects long-term drift). Install MPU6050 by Electronic Cats from Library Manager.

Wiring — MPU-6050 to Arduino VCC → 3.3V  |  GND → GND  |  SDA → A4  |  SCL → A5
I²C address: 0x68 (AD0 pin low, default) or 0x69 (AD0 pin high)
ARDUINO C++ — imu_attitude.ino
// MPU-6050 IMU — PITCH & ROLL with COMPLEMENTARY FILTER // Fuses gyroscope (fast but drifts) with accelerometer (slow but stable) #include <Wire.h> #include <MPU6050.h> MPU6050 mpu; float pitch = 0.0f, roll = 0.0f; unsigned long lastTime = 0; // Complementary filter coefficient // 0.98 = trust gyro 98% each step, correct with accel 2% const float ALPHA = 0.98f; void setup() { Wire.begin(); Serial.begin(115200); mpu.initialize(); if (!mpu.testConnection()) { Serial.println("MPU-6050 not found! Check wiring."); while (1); } Serial.println("Time_ms,Pitch_deg,Roll_deg"); lastTime = millis(); } void loop() { // ── Compute time step ───────────────────────────────────────────── unsigned long now = millis(); float dt = (now - lastTime) / 1000.0f; // convert ms → seconds lastTime = now; // ── Read raw sensor data ────────────────────────────────────────── int16_t ax, ay, az, gx, gy, gz; mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz); // ── Convert to physical units ───────────────────────────────────── // Accelerometer: ±2g range → divide by 16384 to get g float acc_x = ax / 16384.0f; float acc_y = ay / 16384.0f; float acc_z = az / 16384.0f; // Gyroscope: ±250°/s range → divide by 131 to get °/s float gyro_x = gx / 131.0f; // pitch rate (°/s) float gyro_y = gy / 131.0f; // roll rate (°/s) // ── Accelerometer tilt angles from gravity direction ────────────── float acc_pitch = atan2(acc_x, sqrt(acc_y*acc_y + acc_z*acc_z)) * 180.0f/PI; float acc_roll = atan2(acc_y, acc_z) * 180.0f/PI; // ── Complementary filter ────────────────────────────────────────── // angle = α*(angle + gyro*dt) + (1-α)*accel_angle // Gyro integration gives smooth fast response // Accel correction removes long-term drift pitch = ALPHA * (pitch + gyro_x * dt) + (1.0f - ALPHA) * acc_pitch; roll = ALPHA * (roll + gyro_y * dt) + (1.0f - ALPHA) * acc_roll; Serial.print(now); Serial.print(","); Serial.print(pitch, 2); Serial.print(","); Serial.println(roll, 2); delay(10); // 100 Hz update rate }
>> Serial Monitor (115200 baud)Time_ms,Pitch_deg,Roll_deg 120,0.24,-0.12 ← flat on desk, near-zero angles 130,0.24,-0.11 140,6.18,-0.11 ← front edge of board lifted ~6° 150,14.73,-0.12 ← tilted further forward 160,29.91,-0.11 ← nearly 30° pitch

PID Controller — Angle Stabilisation with Servo

A PID (Proportional-Integral-Derivative) controller is the inner loop of virtually every autopilot, drone flight controller, and stability system ever built. This project reads pitch from the IMU and drives a servo to hold a commanded angle — the fundamental building block of any stabilised platform. Wiring: MPU-6050 on I²C (A4/A5), servo signal wire on D9.

ARDUINO C++ — pid_stabiliser.ino
// PID ANGLE STABILISER // Reads pitch from MPU-6050, drives servo to hold commanded angle // Wiring: MPU-6050 → A4/A5 (I²C), Servo signal → D9 #include <Wire.h> #include <MPU6050.h> #include <Servo.h> MPU6050 mpu; Servo myServo; // ── PID Gains — tune these for your physical system ─────────────── float Kp = 2.5f; // Proportional: immediate response to error float Ki = 0.04f; // Integral: corrects steady-state offset float Kd = 1.1f; // Derivative: damps oscillations float setpoint = 0.0f; // target pitch angle (degrees) — change to command float pitch = 0.0f; float integral = 0.0f; float prev_error = 0.0f; unsigned long lastTime = 0; const float ALPHA = 0.98f; void setup() { Wire.begin(); mpu.initialize(); myServo.attach(9); // servo on pin 9 (PWM) myServo.write(90); // start at neutral (90° = centre) Serial.begin(115200); Serial.println("Time_ms,Pitch,Setpoint,Error,P,I,D,Output,ServoPos"); lastTime = millis(); } void loop() { unsigned long now = millis(); float dt = (now - lastTime) / 1000.0f; lastTime = now; // Get pitch from complementary filter (same as IMU project) int16_t ax,ay,az,gx,gy,gz; mpu.getMotion6(&ax,&ay,&az,&gx,&gy,&gz); float ax_g = ax/16384.0f, ay_g = ay/16384.0f, az_g = az/16384.0f; float acc_pitch = atan2(ax_g, sqrt(ay_g*ay_g+az_g*az_g)) * 180.0f/PI; pitch = ALPHA*(pitch + gx/131.0f*dt) + (1.0f-ALPHA)*acc_pitch; // ── PID calculation ─────────────────────────────────────────────── float error = setpoint - pitch; // how far from target integral += error * dt; // accumulated error over time integral = constrain(integral,-50,50); // anti-windup clamp float derivative = (error - prev_error) / dt; // rate of change of error prev_error = error; float P_term = Kp * error; float I_term = Ki * integral; float D_term = Kd * derivative; float output = P_term + I_term + D_term; // Map PID output to servo position: 90° = neutral, 0°–180° = range int servoPos = (int)constrain(90 + output, 0, 180); myServo.write(servoPos); Serial.print(now); Serial.print(","); Serial.print(pitch,2); Serial.print(","); Serial.print(setpoint); Serial.print(","); Serial.print(error,2); Serial.print(","); Serial.print(P_term,2); Serial.print(","); Serial.print(I_term,2); Serial.print(","); Serial.print(D_term,2); Serial.print(","); Serial.print(output,2); Serial.print(","); Serial.println(servoPos); delay(10); }
>> Serial Monitor (115200 baud)Time_ms,Pitch,Setpoint,Error,P,I,D,Output,ServoPos 120,0.00,0.00,0.00,0.00,0.00,0.00,0.00,90 ← level, servo centred 130,5.21,0.00,-5.21,-13.03,-0.02,8.75,-4.30,86 ← tilted, servo corrects 140,4.73,0.00,-4.73,-11.83,-0.03,9.60,-2.26,88 150,3.12,0.00,-3.12,-7.80,-0.04,6.24,-1.60,88 ← error reducing

SD Card Data Logger — Rocket Flight Computer

This combines the BMP280 altimeter with an SD card module to build a complete model rocket flight data logger. It records altitude, pressure, and temperature at 50 Hz to a CSV file for post-flight analysis in MATLAB. The SD card uses SPI protocol. Format your SD card as FAT32 before use.

Additional Wiring — SD Card Module (SPI) CS → D10  |  MOSI → D11  |  MISO → D12  |  SCK → D13  |  VCC → 5V  |  GND → GND
BMP280 stays on I²C: SDA → A4, SCL → A5, VCC → 3.3V
ARDUINO C++ — rocket_logger.ino
// ROCKET FLIGHT DATA LOGGER // Records BMP280 altitude at 50 Hz to SD card as CSV // Libraries: Adafruit BMP280, SD (built into Arduino IDE) #include <Wire.h> #include <SPI.h> #include <SD.h> #include <Adafruit_BMP280.h> const int SD_CS = 10; // SD card chip select pin const int LOG_INTERVAL = 20; // 20 ms = 50 Hz Adafruit_BMP280 bmp; File logFile; float P0 = 0.0f; // ground pressure float maxAlt = 0.0f; // apogee tracker unsigned long lastLog = 0; void setup() { Serial.begin(115200); // Initialise BMP280 if (!bmp.begin(0x76)) { Serial.println("BMP280 fail"); while(1); } // Initialise SD card if (!SD.begin(SD_CS)) { Serial.println("SD fail"); while(1); } // Create new file with auto-increment (FLT00.CSV, FLT01.CSV ...) char filename[] = "FLT00.CSV"; for (int i = 0; i < 100; i++) { filename[3] = '0' + i/10; filename[4] = '0' + i%10; if (!SD.exists(filename)) break; } logFile = SD.open(filename, FILE_WRITE); logFile.println("Time_ms,Pressure_Pa,Temp_C,Alt_AGL_m,MaxAlt_m"); logFile.flush(); // Ground pressure calibration float sum = 0; for(int i=0; i<50; i++){ sum+=bmp.readPressure(); delay(20); } P0 = sum/50.0f; Serial.print("Logging to: "); Serial.println(filename); Serial.print("Ground P0 = "); Serial.println(P0, 1); } void loop() { // Non-blocking timing using millis() — much better than delay() if (millis() - lastLog < LOG_INTERVAL) return; lastLog = millis(); float P = bmp.readPressure(); float T = bmp.readTemperature(); float alt = (288.15f/0.0065f) * (1.0f - pow(P/P0, 287.058f*0.0065f/9.80665f)); if (alt > maxAlt) maxAlt = alt; // track apogee // Write to SD — use print() not println() for speed except last field logFile.print(millis()); logFile.print(","); logFile.print(P,1); logFile.print(","); logFile.print(T,2); logFile.print(","); logFile.print(alt,2); logFile.print(","); logFile.println(maxAlt,2); // Flush to disk every 50 records (every second) to prevent data loss static int count = 0; if (++count % 50 == 0) logFile.flush(); // Echo to serial for live monitoring Serial.print("Alt: "); Serial.print(alt,1); Serial.print(" m MaxAlt: "); Serial.print(maxAlt,1); Serial.println(" m"); }
>> Serial Monitor (115200 baud) + FLT00.CSV on SD cardLogging to: FLT00.CSV Ground P0 = 101234.5 Alt: 0.0 m MaxAlt: 0.0 m ← on pad, pre-launch Alt: 0.0 m MaxAlt: 0.0 m Alt: 23.4 m MaxAlt: 23.4 m ← ascending Alt: 67.8 m MaxAlt: 67.8 m Alt: 94.2 m MaxAlt: 94.2 m ← approaching apogee Alt: 91.5 m MaxAlt: 94.2 m ← descending — apogee = 94.2 m

Explore more
on AerospaceKit.

Post-Processing
MATLAB Analysis

Import your Arduino CSV flight data into MATLAB. Plot altitude vs time, apply FFT to vibration data, and reconstruct trajectories.

Apply To
Rockets & Orbital Mechanics

The data logger above is a complete model rocket flight computer. Learn the trajectory physics behind what you are measuring.

Theory
Flight Mechanics

The complementary filter and PID controller implement flight mechanics theory — stability, damping, and control loops in hardware.

Related
Propulsion

Measure engine thrust, monitor combustion chamber pressure, and log turbine RPM with Arduino sensors.

Projects
Dissertation Ideas

IMU attitude estimator accuracy, Arduino altimeter vs ISA validation, and PID tuning for quadrotors — all with methodologies.

Start Here
Intro to Aerospace

Understand the engineering context behind your hardware projects — where sensors, control systems, and data logging fit in aerospace.

Also by Noor Keshaish

Interested in coding?

SheCodes Lab teaches Python and C++ from scratch — side by side, free, no experience needed. Includes an engineering module covering NumPy, pandas, ISA models, cost index, and flight data analysis. The same tools used to build the calculators on this site.

shecodeslab.com  →
SheCodes Lab
Python & C++