The goal of this project is to integrate an accelerometer (ADXL345) and a magnetometer (HMC5883L) using I2C communication with an Arduino. The data from these sensors will be transmitted to a Processing-based visualization tool. The accelerometer measures linear acceleration along three axes (X, Y, Z), and the magnetometer measures the Earth's magnetic field along these axes. The data is used to visualize the sensor readings in 3D space and create a compass-like display.
Hardware Components:
- ADXL345 Accelerometer:
- I2C address: 0x53
- Measures acceleration on the X, Y, and Z axes.
- Range: ±4g (configured in the code).
- HMC5883L Magnetometer:
- I2C address: 0x1E
- Measures the magnetic field on the X, Y, and Z axes.
- Used to simulate a compass for orientation.
- Arduino (Controller):
- Communicates with both the accelerometer and magnetometer via I2C.
- Sends sensor data to a PC over serial communication.
- Processing (Visualization):
- Displays sensor data visually on a 3D canvas.
- Provides real-time 3D visualizations for the accelerometer and magnetometer data.
Software Components:
- Arduino Code:
- Configures and reads data from the ADXL345 accelerometer and HMC5883L magnetometer using I2C.
- Calibrates the accelerometer by averaging multiple readings.
- Sends the accelerometer and magnetometer data to the serial port in CSV format.
- #include <Wire.h>
- #define SENSOR 0x53 // ADXL345 I2C address
- #define MAGNETOMETER 0x1E // HMC5883L I2C address
- #define POWER_CTL 0x2D
- #define DATA_FORMAT 0x31
- #define DATA_REG 0x32
- int16_t xOffset = 0, yOffset = 0, zOffset = 0;
- void setup() {
- Wire.begin();
- Serial.begin(9600);
- // Initialize ADXL345
- Wire.beginTransmission(SENSOR);
- Wire.write(POWER_CTL);
- Wire.write(0x08); // Set to measurement mode
- Wire.endTransmission();
- Wire.beginTransmission(SENSOR);
- Wire.write(DATA_FORMAT);
- Wire.write(0x01); // Full resolution, +/-4g
- Wire.endTransmission();
- // Initialize Magnetometer
- setupMagnetometer();
- Serial.println("Sensor initialized!");
- calibrate();
- }
- void loop() {
- // Read accelerometer values
- int16_t ax = readAxis(0) - xOffset;
- int16_t ay = readAxis(2) - yOffset;
- int16_t az = readAxis(4) - zOffset;
- // Read magnetometer values
- int16_t mx, my, mz;
- readMagnetometer(mx, my, mz);
- // Send accelerometer and magnetometer data
- Serial.print(ax); Serial.print(",");
- Serial.print(ay); Serial.print(",");
- Serial.print(az); Serial.print(",");
- Serial.print(mx); Serial.print(",");
- Serial.print(my); Serial.print(",");
- Serial.println(mz);
- delay(100);
- }
- int16_t readAxis(uint8_t offset) {
- Wire.beginTransmission(SENSOR);
- Wire.write(DATA_REG + offset);
- Wire.endTransmission();
- Wire.requestFrom(SENSOR, 2);
- if (Wire.available() == 2) {
- return (Wire.read() | (Wire.read() << 8));
- }
- return 0;
- }
- void setupMagnetometer() {
- Wire.beginTransmission(MAGNETOMETER);
- Wire.write(0x00); // Configuration Register A
- Wire.write(0x70); // 8 samples averaged, 15 Hz data output rate
- Wire.endTransmission();
- Wire.beginTransmission(MAGNETOMETER);
- Wire.write(0x01); // Configuration Register B
- Wire.write(0xA0); // Gain configuration
- Wire.endTransmission();
- Wire.beginTransmission(MAGNETOMETER);
- Wire.write(0x02); // Mode Register
- Wire.write(0x00); // Continuous measurement mode
- Wire.endTransmission();
- }
- void readMagnetometer(int16_t &mx, int16_t &my, int16_t &mz) {
- mx = readMagnetometerAxis(0x03);
- my = readMagnetometerAxis(0x05);
- mz = readMagnetometerAxis(0x07);
- }
- int16_t readMagnetometerAxis(uint8_t reg) {
- Wire.beginTransmission(MAGNETOMETER);
- Wire.write(reg);
- Wire.endTransmission();
- Wire.requestFrom(MAGNETOMETER, 2);
- if (Wire.available() == 2) {
- return (Wire.read() << 8) | Wire.read();
- }
- return 0;
- }
- void calibrate() {
- Serial.println("Calibrating... Keep the device flat and still.");
- int32_t xSum = 0, ySum = 0, zSum = 0;
- int samples = 100;
- for (int i = 0; i < samples; i++) {
- xSum += readAxis(0);
- ySum += readAxis(2);
- zSum += readAxis(4);
- delay(10);
- }
- xOffset = xSum / samples;
- yOffset = ySum / samples;
- zOffset = (zSum / samples) - 256;
- Serial.println("Calibration complete!");
- }
Processing Code:
- Reads the sensor data from the serial port.
- Maps accelerometer values to rotate a 3D box based on X and Y acceleration.
- Uses magnetometer data to simulate a compass, rotating an arrow in the direction of the magnetic field.
import processing.serial.*;
Serial myPort;
float ax = 0, ay = 0, az = 0; // Accelerometer values
float mx = 0, my = 0, mz = 0; // Magnetometer values
void setup() {
size(600, 600, P3D);
println(Serial.list());
String portName = Serial.list()[0]; // Adjust port if necessary
myPort = new Serial(this, portName, 9600);
myPort.bufferUntil('\n');
}
void draw() {
background(200);
lights();
// Read serial data
if (myPort.available() > 0) {
String data = myPort.readStringUntil('\n');
if (data != null) {
println(data);
String[] values = split(trim(data), ',');
if (values.length == 6) { // Ensure correct data length
ax = float(values[0]);
ay = float(values[1]);
az = float(values[2]);
mx = float(values[3]);
my = float(values[4]);
mz = float(values[5]);
}
}
}
// Map accelerometer to rotations
float rotX = map(ax, 256, -256, -PI, PI);
float rotY = map(ay, 256, -256, -PI, PI);
// Draw accelerometer visualization
pushMatrix();
translate(width / 2, height / 2, 0);
rotateX(rotX);