krengo
NO

DIY lean-angle logger

Record your own cycling lean angle with a small ESP32 microcontroller, a BNO055 orientation sensor and a microSD card. This guide covers the parts, wiring, mounting, calibration and code examples that explain the principles.

Krengo is a project under development. This page describes the general approach we are using; it does not promise specific measured results.

What you need

Wiring

The wiring below is an example for a classic ESP32 with these pins available, not every ESP32 variant. Set I2C and SPI pins explicitly in software. Use 3.3 V logic, common ground and modules rated for the chosen supply.

Example wiring for a classic ESP32
SignalESP32 pinNotes
BNO055 VCC3.3 VNot 5 V tolerant
BNO055 GNDGNDCommon ground
BNO055 SDAGPIO 21I2C data
BNO055 SCLGPIO 22I2C clock
SD VCC3.3 VUse a 3.3 V module
SD GNDGNDCommon ground
SD CSGPIO 5Chip select
SD MOSIGPIO 23SPI MOSI
SD MISOGPIO 19SPI MISO
SD SCKGPIO 18SPI clock

Some BNO055 boards have a small voltage regulator and can accept 5 V on their Vin pin, but the I2C lines must still be 3.3 V. Always check the module schematic before wiring.

Mounting the sensor

The sensor should be fixed firmly to the bike. Any vibration or rotation relative to the frame corrupts the measurement. Good mounting locations are:

Static lean angle does not depend on sensor height. During motion, mounting position affects vibration and acceleration. Mount the sensor rigidly, document its axes and record orientation with the bike held upright. Compensate for the mounting transform in analysis.

Calibration

The BNO055 reports calibration status for four subsystems: system, gyroscope, accelerometer and magnetometer. Each returns a value from 0 to 3, where 3 is fully calibrated. You can read them with:

uint8_t sys, gyro, accel, mag;
bno.getCalibration(&sys, &gyro, &accel, &mag);
// Gyro: stationary. Accelerometer: six stable orientations.

Keep the sensor still for gyro calibration. Calibrate the accelerometer in six stable orientations: ±X, ±Y and ±Z upward. Use multi-axis movement, often a figure eight, for the magnetometer, away from magnetic interference. A status of 3 means that subsystem is calibrated; it does not prove riding accuracy.

Reading roll angle

The Adafruit library returns heading, roll and pitch in x(), y() and z() respectively for VECTOR_EULER. These are output names, not an automatic mapping to bike axes. Check sensor axis mapping and mounting with known movements before calling an output bike lean.

imu::Vector<3> euler = bno.getVector(Adafruit_BNO055::VECTOR_EULER);
float heading = euler.x();
float roll    = euler.y();
float pitch   = euler.z();

The BNO055 Euler output has limitations during combined rotations, not only near 90°. Adafruit recommends quaternions for general orientation. The expression below gives conventional ZYX roll from a normalised quaternion in the appropriate coordinate frame; it is not automatically bike lean. Converted Euler angles still have singularities, at pitch ±90° in this convention.

imu::Quaternion q = bno.getQuat();
float sinr_cosp = 2 * (q.w() * q.x() + q.y() * q.z());
float cosr_cosp = 1 - 2 * (q.x() * q.x() + q.y() * q.y());
float rollZYX = atan2(sinr_cosp, cosr_cosp) * 180.0 / PI;

Logging to SD card

20 Hz can be an initial logging design choice. Record actual timestamps, quaternions and calibration status so timing and mounting can be checked later. The CSV snippet below only illustrates file writing using an already calculated roll value; it is not a complete or hardware-verified logger program.

File log = SD.open("/lean.csv", FILE_APPEND);
if (log) {
  log.print(millis());
  log.print(",");
  log.println(roll);
  log.close();
}

Opening and closing for each sample is simple but adds SD work. Continuous logging can keep the file open, using buffered writes and a chosen flush interval. Check return values and measure gaps in sampling. Neither close() nor flush() guarantees protection from data loss or file corruption during power failure; use a controlled shutdown.

Power and runtime

Measure runtime on the actual board, sensor, SD card and power supply combination. Ideally, 1000 mAh / 200 mA gives five hours when current is measured at the battery. Usable capacity, regulator losses, temperature and cutoff voltage change this estimate. The supply also needs headroom for SD write current peaks.

From log file to insight

Check timestamps, missing samples and calibration status before interpreting peak angles. Compare known static tilts and dynamic motion against an independent reference. A moving average can hide peaks and cannot correct systematic orientation errors. Preserve raw data and document any filtering.

Where Krengo fits in

Krengo is building a logger along these lines: ESP32 + BNO055, microSD storage, battery power, and a mount under the saddle. The long-term idea is to make the data useful on a Garmin Edge via Bluetooth. For now, the project is focused on reliable logging and repeatable analysis.

Sources: Adafruit BNO055 guide and FAQ · Adafruit_BNO055 driver source.

Frequently asked questions

Can a BNO055 report bike lean directly?

It reports sensor orientation. Converting that to bike lean requires a known mounting transform and sign convention, plus checks with known tilts and during motion.

Which Euler value is roll in the Adafruit library?

For VECTOR_EULER, x(), y() and z() contain heading, roll and pitch respectively. Those names do not establish the bike axes; verify the mounting and axis mapping.

How should the accelerometer be calibrated?

Hold the sensor still in six orientations, with each positive and negative axis pointing upward in turn. Figure-eight movement is for magnetometer calibration.

Does a calibration score of 3 prove accuracy in corners?

No. It is a calibration status, not a riding accuracy certificate. Test dynamic errors, vibration and mounting alignment separately.

Does closing or flushing an SD file prevent data loss?

No. It helps move buffered data to storage, but unexpected power loss can still lose data or damage a file. Handle write failures and use a controlled shutdown.

Related pages

Back to krengo.pro