Hello, I am part of a university group project and am working on trying to use the bluetooth aspect of the IMU Nano 33 BLE Rev 2 sensor to have the serial monitor data outputted, while the IMU is battery powered. I am running into a lot of errors and problems when trying to do this, if anyone is able to give any tips or advice based on my code. I can give more details too about what the code is doing if that helps, thank you!
#include "Arduino_BMI270_BMM150.h"
// Constants
#define MINIMUM_TILT 20 // Positive threshold for tilt detection in degrees
#define MAXIMUM_TILT -20 // Negative threshold for tilt detection in degrees
#define WAIT_TIME 1000 // How often to run the code (in milliseconds)
#define HAPTIC_PIN 3 // D3 pin for motor
#define BUTTON_PIN 5 // D5 pin for calibration button
#define PWM_FREQUENCY 1 // Frequency of the sine wave (how often we update the PWM value)
#define TILT_THRESHOLD_DURATION 5000 // Time (ms) the tilt condition must be sustained to trigger haptic
// Variables for accelerometer data
float ax, ay, az;
float baselineAX, baselineAY, baselineAZ;
float baselineAXangle, baselineAYangle, baselineAZangle;
bool calibrated = false;
// Timing variables
unsigned long previousMillis = 0;
unsigned long previousSineWaveMillis = 0;
unsigned long tiltStartTime = 0;
// Haptic motor and tilt tracking
bool tiltTimerRunning = false;
bool hapticActive = false;
// Sine wave control
float sineWaveValue = 0;
float frequency = 50; // Hz for the sine wave
const float pi = 3.14159;
void setup() {
Serial.begin(9600);
if (!IMU.begin()) {
Serial.println("Failed to initialize IMU!");
while (1);
}
// Pin configurations
pinMode(HAPTIC_PIN, OUTPUT);
digitalWrite(HAPTIC_PIN, LOW); // Motor off initially
pinMode(BUTTON_PIN, INPUT);
digitalWrite(BUTTON_PIN, LOW); // Button off initially
Serial.println("Place the board at the desired angle and press the button to calibrate.");
previousMillis = millis();
}
void loop() {
buttonStateHandler();
if (!calibrated || !IMU.accelerationAvailable() || digitalRead(BUTTON_PIN) == HIGH)
return; // Skip everything if not calibrated or button pressed
unsigned long currentTime = millis();
if (currentTime - previousMillis < WAIT_TIME)
return; // Wait until the next scheduled check
previousMillis = currentTime;
// Read accelerometer values
IMU.readAcceleration(ax, ay, az);
float angleAX = atan2(ax, sqrt(ay * ay + az * az)) * 180 / PI;
float angleAY = atan2(ay, sqrt(ax * ax + az * az)) * 180 / PI;
float angleAZ = atan2(az, sqrt(ax * ax + ay * ay)) * 180 / PI;
float correctedAX = angleAX - baselineAXangle;
float correctedAY = angleAY - baselineAYangle;
float correctedAZ = angleAZ - baselineAZangle;
Serial.print("Y= ");
Serial.print(correctedAY);
Serial.println(" degrees");
Serial.print("Z= ");
Serial.print(correctedAZ);
Serial.println(" degrees");
// Detect if we are tilted beyond thresholds
bool isTilted = (correctedAY > MINIMUM_TILT || correctedAY < MAXIMUM_TILT ||
correctedAZ > MINIMUM_TILT || correctedAZ < MAXIMUM_TILT);
if (isTilted) {
if (!tiltTimerRunning) {
tiltTimerRunning = true;
tiltStartTime = currentTime;
Serial.println("Tilt detected! Timer started.");
}
// Check how long we've been tilted
if (tiltTimerRunning && (currentTime - tiltStartTime >= TILT_THRESHOLD_DURATION)) {
// Tilt sustained for 5 seconds, activate haptics
if (!hapticActive) {
Serial.println("Tilt sustained for 5 seconds! Haptic motor ON.");
hapticActive = true;
}
runHapticMotor(currentTime);
} else {
// Not past 5 seconds yet
Serial.print("Holding tilt for ");
Serial.print((currentTime - tiltStartTime) / 1000);
Serial.println(" seconds...");
analogWrite(HAPTIC_PIN, 0); // Ensure motor is off until timer expires
}
} else {
// Tilt condition ended before timer expired -> reset
if (tiltTimerRunning || hapticActive) {
Serial.println("Tilt ended. Resetting timer and turning motor off.");
}
tiltTimerRunning = false;
hapticActive = false;
analogWrite(HAPTIC_PIN, 0); // Turn off motor immediately
}
}
void buttonStateHandler() {
int buttonState = digitalRead(BUTTON_PIN);
if (buttonState == HIGH) {
calibrateAccelerometer();
calibrated = true;
}
}
void runHapticMotor(unsigned long currentTime) {
if (currentTime - previousSineWaveMillis >= (1000 / PWM_FREQUENCY)) {
previousSineWaveMillis = currentTime;
sineWaveValue = sin(2 * pi * frequency * currentTime / 1000.0);
int pwmValue = map(sineWaveValue, -1, 1, 0, 255);
analogWrite(HAPTIC_PIN, pwmValue);
Serial.print("PWM: ");
Serial.println(pwmValue);
}
}
void calibrateAccelerometer() {
float sumAX = 0, sumAY = 0, sumAZ = 0;
int samples = 500;
analogWrite(HAPTIC_PIN, 0); // Turn off motor during calibration
Serial.println("Calibrating Accelerometer... Hold the board steady.");
for (int i = 0; i < samples; i++) {
while (!IMU.accelerationAvailable());
IMU.readAcceleration(ax, ay, az);
sumAX += ax;
sumAY += ay;
sumAZ += az;
delay(10);
}
// Store baseline offset
baselineAX = sumAX / samples;
baselineAY = sumAY / samples;
baselineAZ = sumAZ / samples;
// Calculate tilt angles of baseline values in degrees
baselineAXangle = atan2(baselineAX, sqrt(baselineAY * baselineAY + baselineAZ * baselineAZ)) * 180 / PI;
baselineAYangle = atan2(baselineAY, sqrt(baselineAX * baselineAX + baselineAZ * baselineAZ)) * 180 / PI;
baselineAZangle = atan2(baselineAZ, sqrt(baselineAX * baselineAX + baselineAY * baselineAY)) * 180 / PI;
Serial.println("Calibration complete!");
Serial.print("Baseline X: "); Serial.println(baselineAXangle, 3);
Serial.print("Baseline Y: "); Serial.println(baselineAYangle, 3);
Serial.print("Baseline Z: "); Serial.println(baselineAZangle, 3);
// Provide calibration feedback via haptic motor (short buzz)
unsigned long currentTime = millis();
previousSineWaveMillis = currentTime;
sineWaveValue = sin(2 * pi * frequency * currentTime / 1000.0);
int pwmValue = map(sineWaveValue, -1, 1, 0, 255);
analogWrite(HAPTIC_PIN, pwmValue);
delay(100);
analogWrite(HAPTIC_PIN, 0);
delay(100);
analogWrite(HAPTIC_PIN, pwmValue);
delay(100);
analogWrite(HAPTIC_PIN, 0);
}