1. The idea

For networking between microcontrollers, I want to send sensor data wirelessly as a test for my final project. For the final project, I will have a audio signal processing unit (most likely implemented with Teensy 4.0) that’s taking input from my bass, modifying the signal and then output to the bass amp. It will receive information from the cyber mouse (aka the random spike generator with sensors) wirelessly, whose firing frequency depends on its proximity to an object, and generates burst firing when accelerates fast enough. The spike timing will then trigger the audio effect board to modulate the bass signal.

2. The making of cyber mouse board

To achieve this, I designed a PCB around Xiao RP2040 with pinheaders configured to be connected to the MPU6050 3-axis gyroscope & 3-axis accelerometer, nRF24L01 wireless module, LCD with I2C module, and a 4.99M ohm pull-down resistor on pin D0 for capacitance sensing. I feel much more confident this week drawing schematics and routing wires in KiCAD, which is a nice feeling.

The schematics

The schematics

The routing

The routing

Milliing this board on Carvera takes around 15 mins, which is fine. However, I did have to go through several iterations before making a functional board. The through hole pads in the first version were a bit too small, and my poor soldering skill didn’t help. I couldn’t solder 2 pins on the top right corner properly, and after trying for 40+ mins on that final two pins, I decided to just design a better board. I increased the pad size by making it an oval pad, with x=2.5mm & y=2mm and keeping the hole diameter to 1mm. This created nice big pads for easy and nice soldering, however after milling this I immediately realized that as I increased the pad size, some of them are now overlapping with the traces. I attempted to cut the connected traces with a knife but quickly decided to just space out the traces and mill one more time instead. This time it turned out pretty and I am more experienced in soldering on copper now as well. The board is now finally ready. In the end, I set the minimun trace width 0.35mm thick, with a minimum clearance of 0.5mm, which I think can be set to 0.6mm next time. The mod parameter is also slightly adjusted as below which worked well.

Mod parameter

Mod parameter

The failed boards

The failed boards

The soldered board

The soldered board

The MPU6050 behind

The MPU6050 behind

I then connected the pins on the board to nRF24L01 with jumper wires for now, which I plan to fully incorporate on the board once I’m more certain about it. Since the Teensy 4.0 I got doesn’t seem to power up when connected, I’ll use another Xiao RP2040 as the receiver to test the wireless communication this week.

3. Sending info wirelessly

There are many libraries for MPU6050 for both Arduino IDE and MicroPython, and I tried many before stumbling across this clearly documented library for Arduino IDE that works right out of the box: MPU6050_light. It’s simpler for nRF24L01 library, and I followed the suggestions by ChatGPT 4o and installed RF24.

I tested the RF module by sending text message between the two boards first, and it worked! It’s very simple but magical, and now it’s time to send some sensor data. The MPU6050_light library included simple functions to acquire accelaration, angular speed, and angle of the board. As a test I gathered the 3 axis angle data first and printed out the value with the serial monitor. After making sure this worked, I then sent the x angle data to my receiver board. I tried to power the transmitter board with a power bank because eventually I want this to be a stand alone device and don’t want it to be tethered to the computer. In theory this should just work, but it kept failing to send the angle data to the receiver. I then added some code for the built-in LED to indicate transmission status, and realized that it is not even running the loop. I was pretty confused and discussed this with ChatGPT, which it suggested a bunch of standard debugging techniques on changing the USB C cord and checking connections and stuffs, but those were not the issue. It then suggested that maybe initializing serial port without a monitor can cause problem, which makes perfect sense. After disabling all related lines of code, it is now finally sending data wirelessly while connected to a power bank! This is a successful test and I am more confident about building this wireless random spike generator for my final project now.

Transmitter Code:

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <Wire.h>
#include <MPU6050_light.h>

// CE and CSN pins for nRF24L01
#define CE_PIN D2
#define CSN_PIN D7

// Capacitive sensing setup (disabled for now)
// #define PROXIMITY_PIN D0 // Pin used for capacitance sensing

RF24 radio(CE_PIN, CSN_PIN); // Create an RF24 object
const byte address[6] = "00001"; // Address of the receiver

// Initialize MPU6050
MPU6050 mpu(Wire);
unsigned long timer = 0;

void setup() {
  pinMode(LED_BUILTIN, OUTPUT); // Set the built-in LED pin as output, for monitoring transmission status

  // Start I2C communication
  Wire.begin();

  // Start serial monitor for testing, disabled when using power bank otherwise there will be error
  // Serial.begin(9600);
  // while (!Serial); // Wait for Serial Monitor
  // Serial.println("Transmitter Starting...");

  if (!radio.begin()) {
    // Serial.println("nRF24L01 not connected!");
    while (1); // Halt
  }

  radio.openWritingPipe(address); // Set the address of the receiver
  radio.setPALevel(RF24_PA_HIGH); // Power Amplifier level
  radio.setChannel(108); // Channel (0-125)
  radio.setDataRate(RF24_1MBPS); // Data rate
  radio.stopListening(); // Set the module as transmitter

  byte status = mpu.begin();
  // Serial.print(F("MPU6050 status: "));
  // Serial.println(status);
  while(status!=0){ } // stop everything if could not connect to MPU6050
  
  // Serial.println(F("Calculating offsets, do not move MPU6050"));
  delay(1000);
  mpu.upsideDownMounting = true;
  mpu.calcOffsets(); // gyro and accelero
  // Serial.println("Done\n");
}

void loop() {
  mpu.update();
  float x;
  float y;
  float z;
  x=mpu.getAngleX();
  y=mpu.getAngleY();
  z=mpu.getAngleZ();
	// Serial.print("X : ");
	// Serial.print(x);
	// Serial.print("\tY : ");
	// Serial.print(y);
	// Serial.print("\tZ : ");
	// Serial.print(z);

  // Send the message
  bool success = radio.write(&x, sizeof(x));

  if (success) {
    // Serial.println("Message sent successfully!");
    digitalWrite(LED_BUILTIN, HIGH); // Turn the LED on
    delay(100);
    digitalWrite(LED_BUILTIN, LOW);  // Turn the LED off
    delay(100);
  } else {
    // Serial.println("Message failed to send!");
  }

  delay(300); // Delay between messages
}

// // Function to measure capacitance on a pin
// for a brief moment it worked, disabled for now
// uint32_t measureCapacitance(uint8_t pin) {
//   uint32_t count = 0;

//   // Discharge the pin
//   pinMode(pin, OUTPUT);
//   digitalWrite(pin, LOW);
//   delayMicroseconds(1);

//   // Set the pin to INPUT and count time to go HIGH
//   pinMode(pin, INPUT);
//   while (digitalRead(pin) == LOW && count < 500000) { // Extended timeout
//     count++;
//   }

//   // Debugging output
//   Serial.print("Measured Capacitance Count: ");
//   Serial.println(count);

//   return count; // Higher count = more capacitance
// }

Receiver Code:

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

// CE and CSN pins for nRF24L01
#define CE_PIN D0
#define CSN_PIN D7

RF24 radio(CE_PIN, CSN_PIN); // Create an RF24 object
const byte address[6] = "00001"; // Address of the transmitter

void setup() {
  Serial.begin(9600);
  while (!Serial); // Wait for Serial Monitor
  Serial.println("Receiver Starting...");

  if (!radio.begin()) {
    Serial.println("nRF24L01 not connected!");
    while (1); // Halt
  }

  radio.openReadingPipe(0, address); // Set the address of the transmitter
  radio.setPALevel(RF24_PA_HIGH); // Power Amplifier level
  radio.setChannel(108); // Channel (0-125)
  radio.setDataRate(RF24_1MBPS); // Data rate
  radio.startListening(); // Set the module as receiver
}

void loop() {
  if (radio.available()) {
    float value=0; // Variable to store the received value
    radio.read(&value, sizeof(value)); // Read the received data
    Serial.print("Received message: ");
    Serial.println(value); // Print the message
  }
}
It worked!

It worked!

4. Group Assignment

For the group assignment, we wanted to send the theremin data from Kyle to control Hye Jun’s servo for her mouse. We used the built-in wifi module of ESP32C6 to communicate.

Group

Group