Skip to content

Week 4 Individual Assignment: Developing Applications for XIAO MG24 Sense Using AI

After completing the embedded development practice with XIAO MG24 Sense, we're now familiar with the basic Arduino programming environment, how to add development boards and libraries in Arduino IDE, and how to upload programs to the board. With this foundation, we can now use natural language to describe our requirements to AI and obtain the needed programs.

We have two previous examples: a Blink program and an IMU test. I want to combine these two examples to create a program that controls LED brightness based on the average acceleration from the IMU accelerometer - the more vigorously I shake the XIAO MG24, the brighter the LED becomes.

I'm calling this project: XIAO MG24's Crazy LED Brightness Meter

How to Write Programming Prompts

When describing programming requirements to AI, a good prompt should include the following elements:

  1. Goal Description
    • Clearly state what functionality you want to achieve
    • Describe expected behavior in simple language
  2. Available Resources
    • Specify what hardware/development board is being used
    • List available sensors/components
    • Mention relevant existing code examples
  3. Specific Requirements
    • Point out key technical parameters
    • Explain specific implementation methods
    • State performance or other constraints
  4. Output Expectations
    • Whether you want complete code or just a framework
    • If comments/explanations are needed
    • If debugging suggestions are required

Example Prompt for the Crazy Brightness Meter

Based on these principles, we can describe the Crazy Brightness Meter requirements like this:

I want to develop a program that makes the XIAO MG24 Sense's LED brightness vary with shaking intensity. Specific requirements:

  1. Hardware:
  • Using XIAO MG24 Sense development board
  • Using onboard LSM6DS3TR-C six-axis sensor's accelerometer function
  • Controlling onboard user LED
  1. Functional Requirements:
  • Read three-axis acceleration data
  • Calculate average of three-axis acceleration as shaking intensity
  • Map shaking intensity to LED brightness
  • LED brightness range: 0-255
  • Recommended sampling frequency: 100ms
  1. Reference Code:
  • Can reference LED control part from Blink example
  • Can reference sensor initialization and data reading from IMU test program Please provide complete code with comments for key sections.

Various AI large language models are rapidly iterating and updating. You can choose your preferred AI to complete this exercise. Below, I'll use Claude to test if the AI's programming output meets our expectations.

I initially planned to use DeepSeek, but this AI was still unstable when I was writing this document, repeatedly showing "Server busy, please try again later" after several conversations. So I used the more stable Claude to complete this exercise.

Using Claude for Programming

I selected the Claude 3.5 Sonnet model in the Claude chat window, then copied the prompt I had written along with the IMU test program and Blink program, as shown below. Note that Claude doesn't support uploading Arduino .ino files directly, so I pasted the example programs directly into the chat window.

Entering requirements and example programs in the Claude chat window

Claude quickly output the required program with comments and explanations.

Claude output the program and explanations according to requirements

Here's the program Claude output initially:

c
#include "LSM6DS3.h"
#include "Wire.h"

// Initialize IMU with I2C communication
LSM6DS3 myIMU(I2C_MODE, 0x6A);

// Constants for LED control
const int MIN_BRIGHTNESS = 0;
const int MAX_BRIGHTNESS = 255;
// Threshold values for acceleration mapping (can be adjusted)
const float MIN_ACCEL = 0.0;    // Minimum acceleration magnitude
const float MAX_ACCEL = 3.0;    // Maximum acceleration magnitude
const int SAMPLE_DELAY = 100;   // 100ms sampling interval

void setup() {
  Wire.begin();
  Serial.begin(115200);
  
  // Initialize LED pin as output
  pinMode(LED_BUILTIN, OUTPUT);
  
  // Wait for IMU initialization
  delay(1000);
  
  // Check if IMU is properly connected
  if (myIMU.begin() != 0) {
    Serial.println("IMU device error");
  } else {
    Serial.println("IMU initialized successfully!");
  }
}

void loop() {
  // Read acceleration values from three axes
  float accelX = myIMU.readFloatAccelX();
  float accelY = myIMU.readFloatAccelY();
  float accelZ = myIMU.readFloatAccelZ();
  
  // Calculate magnitude of acceleration (shaking intensity)
  // Using absolute values to capture movement in any direction
  float shakingIntensity = (abs(accelX) + abs(accelY) + abs(accelZ)) / 3.0;
  
  // Map shaking intensity to LED brightness
  // Constrain input to prevent values outside our desired range
  shakingIntensity = constrain(shakingIntensity, MIN_ACCEL, MAX_ACCEL);
  int brightness = map(shakingIntensity * 100, 
                      MIN_ACCEL * 100, 
                      MAX_ACCEL * 100, 
                      MIN_BRIGHTNESS, 
                      MAX_BRIGHTNESS);
  
  // Set LED brightness using PWM
  analogWrite(LED_BUILTIN, brightness);
  
  // Print values for debugging (optional)
  Serial.print("Acceleration (X,Y,Z): ");
  Serial.print(accelX); Serial.print(", ");
  Serial.print(accelY); Serial.print(", ");
  Serial.print(accelZ); Serial.print(" | ");
  Serial.print("Intensity: ");
  Serial.print(shakingIntensity);
  Serial.print(" | Brightness: ");
  Serial.println(brightness);
  
  // Wait for next sample
  delay(SAMPLE_DELAY);
}

I copied the program to Arduino IDE and uploaded it. There were no errors, and when I opened the serial monitor, I could see the continuous output of acceleration values and expected LED brightness values.

After successfully uploading the program, the XIAO MG24's LED stayed on constantly, only dimming when I shook the XIAO vigorously. This wasn't what we wanted.

Correcting the Program Through AI Feedback

I had a general idea of what was wrong, but for beginners who aren't familiar with programming principles, you can simply describe the behavior to Claude and let it improve the program.

I continued describing the situation to Claude in the chat window, and Claude provided a modified program, as shown below.

Now the LED is on, but it's lit when the XIAO is still and dims when shaking. Looking at the serial monitor output, it's correct - when shaking vigorously, the LED brightness value becomes 255

After further describing the phenomenon to Claude, the AI provided a modified program

Here's the modified program:

c
#include "LSM6DS3.h"
#include "Wire.h"

// Create IMU object using I2C communication mode
LSM6DS3 myIMU(I2C_MODE, 0x6A);

// Define LED control constants
const int LED_PIN = LED_BUILTIN;  // Use onboard LED
const int PWM_MAX = 255;          // Maximum PWM value
const int SAMPLE_INTERVAL = 100;   // Sampling interval (ms)

// Define acceleration thresholds
const float MIN_ACC = 0.0;        // Minimum acceleration value
const float MAX_ACC = 3.0;        // Maximum acceleration value (adjustable based on actual needs)

void setup() {
  // Initialize serial communication for debugging
  Serial.begin(115200);
  Wire.begin();
  delay(1000);

  // Initialize LED pin as output
  pinMode(LED_PIN, OUTPUT);

  // Initialize IMU sensor
  if (myIMU.begin() != 0) {
    Serial.println("IMU initialization failed!");
    while (1);  // Stop program if initialization fails
  }
  Serial.println("IMU initialization successful!");
}

void loop() {
  // Read three-axis acceleration data
  float accX = abs(myIMU.readFloatAccelX());
  float accY = abs(myIMU.readFloatAccelY());
  float accZ = abs(myIMU.readFloatAccelZ());

  // Calculate shake intensity (average of three-axis acceleration)
  float shakeIntensity = (accX + accY + accZ) / 3.0;

  // Map shake intensity to LED brightness (0-255)
  int brightness = map(
    constrain(shakeIntensity * 100, MIN_ACC * 100, MAX_ACC * 100),
    MIN_ACC * 100,
    MAX_ACC * 100,
    0,
    PWM_MAX
  );

  // Invert PWM value because LED is active-low
  brightness = PWM_MAX - brightness;

  // Output debug information
  Serial.print("Acceleration: X=");
  Serial.print(accX);
  Serial.print(" Y=");
  Serial.print(accY);
  Serial.print(" Z=");
  Serial.print(accZ);
  Serial.print(" Shake Intensity=");
  Serial.print(shakeIntensity);
  Serial.print(" LED Brightness=");
  Serial.println(brightness);

  // Set LED brightness
  analogWrite(LED_PIN, brightness);

  // Wait for next sample
  delay(SAMPLE_INTERVAL);
}

I copied the program to Arduino IDE again, and now when XIAO is idle, the LED is on, but it will turn off when shaken violently. I have resubmitted the feedback.

When XIAO is still, the LED is on, but it will turn off if it shakes violently.

Claude provided a third version of the program, as shown below.

Claude provided a third version of the program

Here's the output program:

c
#include "LSM6DS3.h"
#include "Wire.h"

// Create IMU object using I2C communication mode
LSM6DS3 myIMU(I2C_MODE, 0x6A);

// Define LED control constants
const int LED_PIN = LED_BUILTIN;  // Use onboard LED
const int PWM_MAX = 255;          // Maximum PWM value
const int SAMPLE_INTERVAL = 100;   // Sampling interval (ms)

// Define acceleration-related parameters
const float GRAVITY = 1.0;        // Gravity acceleration reference value
const float MIN_ACC = 0.0;        // Minimum acceleration change value
const float MAX_ACC = 2.0;        // Maximum acceleration change value

// For storing previous acceleration values
float lastAccX = 0;
float lastAccY = 0;
float lastAccZ = 0;

void setup() {
  // Initialize serial communication for debugging
  Serial.begin(115200);
  Wire.begin();
  delay(1000);

  // Initialize LED pin as output
  pinMode(LED_PIN, OUTPUT);

  // Initialize IMU sensor
  if (myIMU.begin() != 0) {
    Serial.println("IMU initialization failed!");
    while (1);  // Stop program if initialization fails
  }
  Serial.println("IMU initialization successful!");

  // Read initial acceleration values
  lastAccX = myIMU.readFloatAccelX();
  lastAccY = myIMU.readFloatAccelY();
  lastAccZ = myIMU.readFloatAccelZ();
}

void loop() {
  // Read current acceleration data
  float accX = myIMU.readFloatAccelX();
  float accY = myIMU.readFloatAccelY();
  float accZ = myIMU.readFloatAccelZ();

  // Calculate acceleration changes (removing gravity effect)
  float deltaX = abs(accX - lastAccX);
  float deltaY = abs(accY - lastAccY);
  float deltaZ = abs(accZ - lastAccZ);

  // Update previous acceleration values
  lastAccX = accX;
  lastAccY = accY;
  lastAccZ = accZ;

  // Calculate overall shake intensity (average of three-axis acceleration changes)
  float shakeIntensity = (deltaX + deltaY + deltaZ) / 3.0;

  // Map shake intensity to LED brightness (0-255)
  int brightness = map(
    constrain(shakeIntensity * 100, MIN_ACC * 100, MAX_ACC * 100),
    MIN_ACC * 100,
    MAX_ACC * 100,
    PWM_MAX,    // Note: Range inverted, PWM_MAX when still (LED off)
    0           // Near 0 when shaking (LED on)
  );

  // Output debug information
  Serial.print("Acceleration changes: X=");
  Serial.print(deltaX);
  Serial.print(" Y=");
  Serial.print(deltaY);
  Serial.print(" Z=");
  Serial.print(deltaZ);
  Serial.print(" Shake Intensity=");
  Serial.print(shakeIntensity);
  Serial.print(" LED Brightness=");
  Serial.println(brightness);

  // Set LED brightness
  analogWrite(LED_PIN, brightness);

  // Wait for next sample
  delay(SAMPLE_INTERVAL);
}

This time, the program worked as expected - when I kept the XIAO still, the LED stayed off, and when I shook it, the LED would light up with brightness varying according to the shaking intensity. As shown below.

Now when shaking the XIAO MG24, the onboard LED lights up

With this experience, you can try some more complex applications. My suggestion is to provide AI with comprehensive background information (documentation, example programs, etc.) when asking questions.