You dont have javascript enabled! Please enable it!

Practical case: BLE gesture gamepad on Arduino Nano 33 BLE

Practical case: BLE gesture gamepad on Arduino Nano 33 BLE — hero

Objective and use case

What you’ll build: Create a BLE gesture gamepad using Arduino Nano 33 BLE, APDS9960, and MPU6050 to stream gamepad states via hand gestures and tilt.

Why it matters / Use cases

  • Enable intuitive gaming controls through hand gestures, enhancing user experience in mobile and PC games.
  • Facilitate accessibility for users with limited mobility by providing alternative input methods.
  • Demonstrate the integration of multiple sensors (APDS9960 for gesture detection and MPU6050 for tilt) in a compact device.
  • Showcase the capabilities of Arduino Nano 33 BLE in developing low-power, wireless applications.

Expected outcome

  • Achieve a latency of less than 50ms between gesture input and gamepad state transmission.
  • Maintain a stable BLE connection with a packet loss rate below 2% during gameplay.
  • Stream gamepad states at a rate of 10 packets per second, ensuring smooth gameplay.
  • Demonstrate accurate gesture recognition with a success rate of over 90% in various lighting conditions.

Audience: Hobbyists and developers interested in IoT and gaming; Level: Intermediate

Architecture/flow: Arduino Nano 33 BLE processes inputs from APDS9960 and MPU6050, transmitting gamepad states via BLE to connected devices.

Advanced Hands‑On: BLE Gesture Gamepad with Arduino Nano 33 BLE + APDS9960 + MPU6050

Objective: Build a BLE “gesture gamepad” that streams a compact gamepad state over Bluetooth Low Energy (BLE), using hand gestures (APDS9960) for D‑pad/button inputs and tilt (MPU6050) for analog axes.

We will develop, build, and flash the firmware using PlatformIO (CLI). The target device is EXACTLY: Arduino Nano 33 BLE + APDS9960 + MPU6050.

Note on tooling policy: The family default is Arduino UNO with Arduino CLI. Because we are using a different board (Arduino Nano 33 BLE, nRF52840), we will use PlatformIO (CLI) as required.


Prerequisites

  • OS:
  • Windows 10/11 (x64) or
  • macOS 12+ or
  • Ubuntu 22.04+ (or equivalent Linux)
  • Software:
  • Python 3.10+ (recommended 3.11+)
  • PlatformIO Core 6.1.13 or newer (CLI)
  • USB cable:
  • High‑quality data cable (USB Micro‑B to USB)
  • BLE Central for validation:
  • Smartphone with Nordic “nRF Connect” app OR
  • Laptop BLE adapter and Python (bleak) for optional host script
  • Drivers:
  • Arduino Nano 33 BLE uses native USB CDC (ACM). Typically no additional drivers are needed on macOS/Linux. Windows 10/11 installs automatically. If Windows driver issues arise, install “Arduino Mbed OS Boards” drivers via Arduino IDE package (only driver component) or allow Windows Update to complete.

Materials (exact model)

  • 1 × Arduino Nano 33 BLE (Model: ABX00030; MCU: nRF52840; 3.3 V I/O only)
  • 1 × APDS9960 gesture/proximity/color breakout (e.g., SparkFun APDS-9960, Part: SEN‑12787; default I2C address 0x39; 3.3 V logic)
  • 1 × MPU6050 6‑axis accelerometer/gyro breakout (common module: GY‑521; default I2C address 0x68; ensure it can run at 3.3 V)
  • 4–8 × Female‑female jumper wires (Dupont)
  • Optional:
  • 1 × Breadboard
  • 2 × additional jumpers if you want to use INT lines for low‑latency gesture interrupts (we’ll use polling by default)

Setup / Connection

The Arduino Nano 33 BLE uses 3.3 V logic. Do not connect 5 V logic to its I/O. Both APDS9960 and MPU6050 operate over I2C; you can connect both sensors in parallel to SDA/SCL.

  • I2C pins on Nano 33 BLE:
  • SDA = A4
  • SCL = A5
  • Power rails:
  • 3V3 pin provides regulated 3.3 V
  • GND for ground reference

We will poll the APDS9960 for gestures (so INT is optional). MPU6050 INT is also optional.

Wire Connections

  • Power:
  • Nano 33 BLE 3V3 → APDS9960 VCC; MPU6050 VCC
  • Nano 33 BLE GND → APDS9960 GND; MPU6050 GND
  • I2C:
  • Nano 33 BLE A4 (SDA) → APDS9960 SDA; MPU6050 SDA
  • Nano 33 BLE A5 (SCL) → APDS9960 SCL; MPU6050 SCL
  • Optional interrupts:
  • APDS9960 INT → D2
  • MPU6050 INT → D3

Ensure your APDS9960 breakout is 3.3 V compatible (SparkFun SEN‑12787 is). Many GY‑521 MPU6050 boards include a regulator; when in doubt, power with 3.3 V and confirm it works reliably at that voltage.

Expected I2C Addresses

  • APDS9960: 0x39
  • MPU6050: 0x68 (AD0 low). If AD0 is tied high, address is 0x69.

Signal/Pin Mapping Table

Function Nano 33 BLE Pin APDS9960 Pin MPU6050 Pin Notes
Power 3V3 VCC VCC 3.3 V only
Ground GND GND GND Common ground
I2C Data A4 (SDA) SDA SDA Shared bus
I2C Clock A5 (SCL) SCL SCL Shared bus
Gesture Interrupt D2 (optional) INT We’ll use polling; hook up if desired
Motion Interrupt D3 (optional) INT We’ll use polling; hook up if desired

Design Overview

  • BLE GATT custom “Gamepad” service with two characteristics:
  • Buttons (1 byte): bitfield for Up/Down/Left/Right, A, B (from APDS9960 gestures)
  • Axes (2 bytes): X, Y in signed int8 range −127..127 based on tilt from MPU6050
  • Gesture mapping:
  • Up/Down/Left/Right gestures map to D‑pad bits.
  • Near/Far gestures map to A/B buttons.
  • Tilt mapping:
  • Roll → X axis; Pitch → Y axis
  • Simple low‑pass filtered accelerometer‑only tilt to avoid gyro drift.
  • Report rate:
  • 50 Hz default (20 ms), with change‑detection to reduce BLE traffic.
  • Debug:
  • Serial log at 115200 baud for quick inspection.

Full Code

Create the PlatformIO project with the following files.

File: platformio.ini

; Project: ble-gesture-gamepad
; Board: Arduino Nano 33 BLE (ABX00030)
; PlatformIO Core >= 6.1.13

[env:nano33ble]
platform = nordicnrf52
board = nano33ble
framework = arduino
upload_protocol = cmsis-dap

; Lock known-good library versions for reproducibility
lib_deps =
  arduino-libraries/ArduinoBLE @ ^1.3.6
  sparkfun/SparkFun APDS9960 RGB and Gesture Sensor @ ^1.4.3
  adafruit/Adafruit MPU6050 @ ^2.2.6
  adafruit/Adafruit Unified Sensor @ ^1.1.14

monitor_speed = 115200

Notes:
– upload_protocol cmsis‑dap works with the Nano 33 BLE’s on‑board debugger. If your upload fails, PlatformIO will fall back to the serial bootloader. You can omit this line if needed.

File: src/main.cpp

#include <Arduino.h>
#include <Wire.h>
#include <ArduinoBLE.h>
#include <SparkFun_APDS9960.h>
#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <math.h>

// ====== Sensor instances ======
SparkFun_APDS9960 apds;
Adafruit_MPU6050 mpu;

// ====== BLE definitions (custom service) ======
// 128-bit UUIDs generated for this project
#define GP_SERVICE_UUID   "12345678-1234-5678-1234-56789abcdef0"
#define GP_BUTTONS_UUID   "12345678-1234-5678-1234-56789abcdef1"
#define GP_AXES_UUID      "12345678-1234-5678-1234-56789abcdef2"

BLEService gpService(GP_SERVICE_UUID);
// Buttons bitfield (1 byte): [bit0:Up][1:Down][2:Left][3:Right][4:A][5:B][6:reserved][7:reserved]
BLECharacteristic btnChar(GP_BUTTONS_UUID, BLERead | BLENotify, 1);
// Axes (2 bytes): int8 X, int8 Y, range -127..127
BLECharacteristic axesChar(GP_AXES_UUID, BLERead | BLENotify, 2);

// ====== Gamepad state ======
volatile uint8_t buttons = 0x00;
int8_t axisX = 0;
int8_t axisY = 0;

// Gesture mapping timings
const uint16_t GESTURE_HOLD_MS = 150; // keep button asserted briefly per gesture
uint32_t gestureHoldUntilMs = 0;
uint8_t gestureBitsLatched = 0;

// Tilt filter
float filtX = 0.0f;
float filtY = 0.0f;
const float alpha = 0.25f; // low-pass filter coeff (0..1)

// Rate limiting
const uint32_t REPORT_INTERVAL_MS = 20; // 50 Hz
uint32_t lastReportMs = 0;

// Helpers
static inline int8_t clampToI8(float v) {
  if (v < -127) return -127;
  if (v > 127) return 127;
  return (int8_t)lroundf(v);
}

void updateAxesFromMPU() {
  sensors_event_t a, g, temp;
  mpu.getEvent(&a, &g, &temp);

  // Compute tilt angles from accelerometer only (degrees)
  // Roll: rotation around X axis, Pitch: around Y axis
  float ax = a.acceleration.x;
  float ay = a.acceleration.y;
  float az = a.acceleration.z;

  // Protect against divide-by-zero issues
  if (isnan(ax) || isnan(ay) || isnan(az)) return;

  float roll  = atan2f(ay, az) * 57.29578f; // deg
  float pitch = atan2f(-ax, sqrtf(ay * ay + az * az)) * 57.29578f; // deg

  // Map angles to -127..127. Choose ~35 deg full-scale for responsiveness.
  const float FS_DEG = 35.0f;
  float xRaw = (roll / FS_DEG) * 127.0f;
  float yRaw = (pitch / FS_DEG) * 127.0f;

  // Dead-zone to avoid jitter
  const float DZ = 4.0f;
  if (fabsf(xRaw) < DZ) xRaw = 0.0f;
  if (fabsf(yRaw) < DZ) yRaw = 0.0f;

  // Low-pass filter
  filtX = (alpha * xRaw) + ((1.0f - alpha) * filtX);
  filtY = (alpha * yRaw) + ((1.0f - alpha) * filtY);

  axisX = clampToI8(filtX);
  axisY = clampToI8(filtY);
}

void processGesture() {
  // Non-blocking polling for gesture
  if (apds.isGestureAvailable()) {
    uint8_t g = apds.readGesture();
    uint8_t newBits = 0;

    switch (g) {
      case DIR_UP:    newBits |= (1 << 0); break; // Up
      case DIR_DOWN:  newBits |= (1 << 1); break; // Down
      case DIR_LEFT:  newBits |= (1 << 2); break; // Left
      case DIR_RIGHT: newBits |= (1 << 3); break; // Right
      case DIR_NEAR:  newBits |= (1 << 4); break; // A
      case DIR_FAR:   newBits |= (1 << 5); break; // B
      default: break;
    }

    if (newBits != 0) {
      gestureBitsLatched = newBits;
      gestureHoldUntilMs = millis() + GESTURE_HOLD_MS;
    }
  }

  // Apply latched gesture bits for a short time window
  uint32_t now = millis();
  if (gestureBitsLatched != 0) {
    if (now <= gestureHoldUntilMs) {
      // Assert gesture bits
      buttons |= gestureBitsLatched;
    } else {
      // Release after hold time
      buttons &= ~gestureBitsLatched;
      gestureBitsLatched = 0;
    }
  }
}

bool publishIfChanged() {
  static uint8_t lastButtons = 0xFF;
  static int8_t lastX = 127, lastY = 127;

  bool changed = false;
  if (buttons != lastButtons) {
    btnChar.writeValue(&buttons, 1);
    lastButtons = buttons;
    changed = true;
  }

  if (axisX != lastX || axisY != lastY) {
    int8_t axes[2] = { axisX, axisY };
    axesChar.writeValue((uint8_t*)axes, 2);
    lastX = axisX; lastY = axisY;
    changed = true;
  }
  return changed;
}

void setupAPDS() {
  if (!apds.init()) {
    Serial.println("[APDS9960] init failed");
  } else {
    // Optional tuning
    apds.setGestureGain(GGAIN_4X);
    apds.setGestureLEDDrive(LED_DRIVE_100MA);
    apds.setGestureProximityThreshold(30);
    apds.enableGestureSensor(true);
    Serial.println("[APDS9960] gesture sensor enabled");
  }
}

void setupMPU() {
  if (!mpu.begin(0x68, &Wire)) {
    Serial.println("[MPU6050] begin failed (check wiring/address)");
    return;
  }
  mpu.setAccelerometerRange(MPU6050_RANGE_4_G);
  mpu.setGyroRange(MPU6050_RANGE_500_DEG);
  mpu.setFilterBandwidth(MPU6050_BAND_21_HZ);
  Serial.println("[MPU6050] online");
}

void setupBLE() {
  if (!BLE.begin()) {
    Serial.println("[BLE] init failed");
    while (1) delay(1000);
  }
  BLE.setDeviceName("Nano33BLE");
  BLE.setLocalName("GestureGamepad");
  BLE.setAdvertisedService(gpService);

  gpService.addCharacteristic(btnChar);
  gpService.addCharacteristic(axesChar);
  BLE.addService(gpService);

  // Initialize characteristic values so a central can read immediately
  uint8_t b = 0;
  int8_t axes[2] = {0, 0};
  btnChar.writeValue(&b, 1);
  axesChar.writeValue((uint8_t*)axes, 2);

  BLE.advertise();
  Serial.println("[BLE] advertising as 'GestureGamepad'");
}

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.begin(115200);
  while (!Serial && millis() < 2500) { /* wait briefly for monitor */ }

  Wire.begin();
  Wire.setClock(400000); // 400 kHz I2C

  setupAPDS();
  setupMPU();
  setupBLE();
}

void loop() {
  // Handle BLE events
  BLEDevice central = BLE.central();

  if (central) {
    Serial.print("[BLE] Connected: "); Serial.println(central.address());

    // Connected loop
    lastReportMs = 0; // force immediate report
    while (central.connected()) {
      updateAxesFromMPU();
      processGesture();

      uint32_t now = millis();
      if (now - lastReportMs >= REPORT_INTERVAL_MS) {
        bool changed = publishIfChanged();
        if (changed) {
          digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); // blink on update
        }
        lastReportMs = now;

        // Debug print (comment out if too chatty)
        Serial.print("btn=0b"); Serial.print(buttons, BIN);
        Serial.print(" X="); Serial.print(axisX);
        Serial.print(" Y="); Serial.println(axisY);
      }
      // Give time to BLE stack
      BLE.poll();
    }

    Serial.println("[BLE] Disconnected");
  }

  // Not connected: still poll BLE stack
  BLE.poll();
}

Key points:
– The APDS9960 is used in gesture mode only; polling avoids wiring INT.
– The MPU6050 uses accelerometer data to derive tilt angles and map them to gamepad axes.
– BLE exposes a custom Gamepad service with two characteristics (buttons, axes). A host app can subscribe to notifications and interpret the gamepad state.


Build / Flash / Run commands

We will use PlatformIO CLI end‑to‑end.

1) Install/verify PlatformIO:

python3 -m pip install --upgrade platformio
pio --version

2) Create project folder and files:

mkdir -p ~/projects/ble-gesture-gamepad/src
cd ~/projects/ble-gesture-gamepad

3) Fetch dependencies and build:

pio pkg install
pio run -e nano33ble

4) Put the board into normal mode (power via USB), then upload:

# Identify the serial port if needed:
pio device list

# Upload firmware
pio run -e nano33ble -t upload

5) Open the serial monitor for debugging output:

pio device monitor -b 115200

6) BLE run procedure:
– Keep the board powered via USB.
– It will advertise as “GestureGamepad”.

Driver notes:
– Windows: The Nano 33 BLE enumerates as a COM port (CDC ACM). No CP210x/CH34x drivers are required.
– macOS/Linux: Appears as /dev/cu.usbmodem (macOS) or /dev/ttyACM (Linux).


Step‑by‑Step Validation

1) I2C sanity check (power and address)

  • Power the board and open the serial monitor:
  • Expect messages like “[APDS9960] gesture sensor enabled” and “[MPU6050] online”.
  • If either init fails, revisit wiring. Ensure both sensors share SDA/SCL/GND/3V3.

Optional: Run an I2C scanner sketch (not provided here) if you suspect bus issues. Expected addresses: 0x39 (APDS9960), 0x68 (MPU6050).

2) BLE advertisement

  • On a smartphone, open “nRF Connect” (iOS or Android).
  • Scan: You should see “GestureGamepad” advertising.
  • Tap it and Connect. In the GATT browser you should see:
  • Service UUID 12345678‑1234‑5678‑1234‑56789abcdef0
  • Characteristics:
    • Buttons (UUID …ef1), length 1
    • Axes (UUID …ef2), length 2

3) Subscribe and observe values

  • In nRF Connect, enable notifications (bell icon) on both characteristics.
  • With the board flat and stationary:
  • Buttons should be 0x00
  • Axes near 0,0 (allow slight noise)
  • Tilt the board:
  • Rolling right should increase X toward +127; left toward −127.
  • Pitching forward/back should move Y accordingly.
  • Perform gestures over the APDS9960 sensor window:
  • Swipe UP: Buttons bit0 set briefly (expect reported byte 0x01 during hold).
  • Swipe DOWN: byte 0x02
  • Swipe LEFT: byte 0x04
  • Swipe RIGHT: byte 0x08
  • NEAR: byte 0x10
  • FAR: byte 0x20

Because the gesture is latched for GESTURE_HOLD_MS (150 ms), you’ll see the corresponding bit asserted briefly after each gesture, then return to zero.

4) Desktop validation with Python (optional)

If you prefer a desktop BLE central, install bleak and run a quick monitor:

python3 -m pip install bleak

Example script (replace MAC/UUIDs as needed by your OS):

# file: host_monitor.py
import asyncio, struct
from bleak import BleakScanner, BleakClient

SERVICE = "12345678-1234-5678-1234-56789abcdef0"
BTN_UUID = "12345678-1234-5678-1234-56789abcdef1"
AX_UUID  = "12345678-1234-5678-1234-56789abcdef2"

async def main():
    print("Scanning for GestureGamepad...")
    dev = None
    devices = await BleakScanner.discover(timeout=5.0)
    for d in devices:
        if "GestureGamepad" in (d.name or ""):
            dev = d
            break
    if not dev:
        print("Device not found.")
        return

    async with BleakClient(dev) as client:
        print("Connected:", dev)
        async def btn_cb(_, data: bytearray):
            btn = data[0]
            print(f"Buttons=0b{btn:08b}")

        async def ax_cb(_, data: bytearray):
            x, y = struct.unpack("bb", data)
            print(f"Axes: X={x:4d}, Y={y:4d}")

        await client.start_notify(BTN_UUID, btn_cb)
        await client.start_notify(AX_UUID, ax_cb)
        print("Listening (Ctrl+C to quit)...")
        while True:
            await asyncio.sleep(1)

if __name__ == "__main__":
    asyncio.run(main())

Run:

python3 host_monitor.py

Perform gestures and tilts. You should see button bitfields and axis values printed in real time.

5) End‑to‑end checks

  • Latency: You should observe <100 ms end‑to‑end from gesture to notification with the default 50 Hz reporting.
  • Stability: Axes should be stable near zero when the board is stationary (thanks to low‑pass filtering and dead‑zone).
  • BLE reconnection: Disconnect from nRF Connect; the device should resume advertising automatically.

Troubleshooting

  • No BLE advertisement:
  • Ensure BLE.begin() succeeded in the serial log. If not, power‑cycle the board and close any BLE central app that might be caching the connection.
  • Avoid multiple centrals connecting at once.

  • Upload fails:

  • Try: pio run -e nano33ble -t upload –upload-port
  • On Windows, check Device Manager for the COM port. On macOS/Linux, check /dev/cu.usbmodem or /dev/ttyACM.
  • Press the reset button twice quickly to enter the bootloader (LED pulsing), then retry upload.

  • APDS9960 not detected:

  • Recheck SDA/SCL orientation. APDS9960 address should be 0x39.
  • Some boards need a clean sensor window; ensure there’s no tape/dust blocking the IR.

  • MPU6050 not detected:

  • Default address is 0x68. If your board ties AD0 high, change code to mpu.begin(0x69).
  • Ensure power at 3.3 V; some GY‑521 boards are flaky at 3.3 V if their regulator drops too much—verify with a multimeter. If the breakout expects 5 V only, replace it with a 3.3 V‑friendly version.

  • Choppy axes or jitter:

  • Increase filter bandwidth smoothing (lower alpha, e.g., 0.15).
  • Increase dead‑zone DZ to 6–8.
  • Reduce REPORT_INTERVAL_MS to 30–40 ms to lower traffic.

  • Gesture misses:

  • Adjust APDS9960 gain/LED drive or proximity threshold; ensure good ambient lighting and keep 3–10 cm above the sensor for swipes.
  • If polling is insufficient, wire INT to a pin and switch to interrupt‑driven reads (SparkFun library supports this pattern).

  • Duplicate I2C pull‑ups:

  • Many breakouts include their own pull‑ups; if you have instability on long wires, prefer a single set of ~4.7 kΩ pull‑ups to 3.3 V or keep wiring short.

  • BLE central sees raw data but you want native OS “gamepad”:

  • This tutorial exposes a custom GATT service. For OS‑recognized gamepad (HID over GATT, HOGP), you’d implement a HID descriptor and HID service. See “Improvements” below.

Improvements

  • BLE HID Gamepad (HOGP):
  • Replace the custom service with a standard HID service (UUID 0x1812) and a Gamepad HID report descriptor (buttons + X/Y axes).
  • The ArduinoBLE library includes HID support on Nano 33 BLE in recent versions; you’ll define a HID report map and input report characteristic, then the device will enumerate as a “Gamepad” on hosts that support HOGP.
  • This yields native compatibility with games and OS input mapping, removing the need for a host‑side script.

  • Interrupt‑driven gesture:

  • Connect APDS9960 INT to a digital pin and attach an ISR or event flag to promptly read gestures, reducing latency and power.

  • Sensor fusion:

  • Use complementary or Kalman filters to blend accelerometer and gyro for smoother axes, especially during dynamic motion.
  • The MPU6050 DMP (Digital Motion Processor) can offload some fusion tasks if you adopt a suitable library.

  • Calibration routine:

  • Record zero‑tilt baseline on startup (press a “calibrate” button), compute offsets, and store in NVM.

  • Battery operation:

  • Power the Nano 33 BLE with a LiPo + charger backpack and manage advertising intervals for power savings.

  • Debounce and gesture customization:

  • Add a gesture queue to handle repeated swipes and differentiate short/long gestures mapped to different buttons.

  • Expand buttons:

  • Use APDS9960 proximity levels to map analog threshold to additional buttons (e.g., “Select/Start”).

Final Checklist

  • Materials
  • Arduino Nano 33 BLE (ABX00030)
  • APDS9960 breakout (SparkFun SEN‑12787 or equivalent, 3.3 V)
  • MPU6050 breakout (GY‑521 or equivalent, 3.3 V safe)
  • Jumpers, USB cable

  • Wiring

  • 3V3 and GND shared to both sensors
  • A4 → SDA on both sensors
  • A5 → SCL on both sensors
  • Optional: APDS INT → D2, MPU INT → D3

  • Software

  • PlatformIO Core installed
  • platformio.ini configured for nano33ble and libraries
  • src/main.cpp created with BLE + APDS9960 + MPU6050 logic
  • Build: pio run -e nano33ble
  • Upload: pio run -e nano33ble -t upload
  • Monitor: pio device monitor -b 115200

  • BLE validation

  • “GestureGamepad” is advertising
  • Connect with nRF Connect
  • Subscribe to buttons and axes characteristics
  • Swipe: buttons bits change briefly
  • Tilt: axes vary in −127..127 range

  • Optional host

  • bleak installed
  • host_monitor.py receives notifications and prints states

  • Troubleshooting

  • Addressed I2C address mismatches, driver notes, and sensor noise
  • Adjusted filter parameters if needed

With this build, you have a working BLE gesture gamepad: APDS9960 handles discrete inputs (D‑pad + buttons), and MPU6050 tilt drives analog axes—streamed over BLE at a fixed rate to any central that subscribes to your custom gamepad service.

Find this product and/or books on this topic on Amazon

Go to Amazon

As an Amazon Associate, I earn from qualifying purchases. If you buy through this link, you help keep this project running.

Quick Quiz

Question 1: What is the primary objective of the project described in the article?




Question 2: Which microcontroller is used in the project?




Question 3: What type of cable is required for the project?




Question 4: Which software is recommended for firmware development?




Question 5: What is the role of the APDS9960 in the project?




Question 6: What operating system is NOT listed as a prerequisite?




Question 7: What type of drivers are typically needed for the Arduino Nano 33 BLE?




Question 8: What is the default I2C address for the MPU6050?




Question 9: Which component is optional for the project?




Question 10: What is the recommended version of Python for this project?




Carlos Núñez Zorrilla
Carlos Núñez Zorrilla
Electronics & Computer Engineer

Telecommunications Electronics Engineer and Computer Engineer (official degrees in Spain).

Follow me:
Scroll to Top