Beschleunigungssensor

Der Beschleunigungssensor ADXL335 (GY-61) belegt 3 analoge Eingänge für die Beschleunigung in x, y bzw. z-Richtung. Der Anschluss ist denkbar einfach: GND an GND, X_OUT, Y_OUT, Z_OUT an drei analoge Pins (z.B.: A3,A4 bzw. A5). VCC wird bei 3,3 Volt angeschlossen (bei neueren Modellen kann es sein, dass man diesen bei 5 V anschliesen muss).

Zusätzlich verbindet man den 3,3 V Anschlußpin noch mit dem ARef-Pin. Woher soll der Analog-Digital-Wandler denn die richtige Spannung kennen? Im Quelltext muss dies ebenfalls im void setup angegeben werden.

Laut Datenblatt misst der Sensor Beschleunigungen bis zu 3 g.

Arduino Quelltext

ADXL auslesen

const int xpin = A3;                  
const int ypin = A4;                  
const int zpin = A5;     

void setup()
{
  Serial.begin(9600);
  // falls 3,3 V mit AREF verbunden
  analogReference(EXTERNAL);
}

void loop()
{
  int x=analogRead(xpin);
  int y=analogRead(ypin);
  int z=analogRead(zpin);
  
  
  Serial.print(x);
  Serial.print("\t");
  Serial.print(y);
  Serial.print("\t");
  Serial.print(z);
  Serial.println();
  delay(200);
}

Physikalisches Prinzip

Im Beschleunigungssensor ist eine Masse elastisch an einer Feder eingebaut. Wird der Sensor bewegt, so wird durch die Trägheit die Masse bewegt und die Feder gedehnt oder gestaucht.

Die Kraft $F$, die die Längenänderung $\Delta  x = d$ bewirkt wird berechnet mit $F = k \cdot d$, wobei $k$ eine Federkonstante ist. Mit dem Newton' schen Bewegungsgesetz $F = m \cdot a$ kann man die Beschleunigung berechnen. ($a = {k \over m}\cdot d$)

Konkret ist die Masse die mittlere Elektrode zweier Plattenkondensatoren. Wirkt auf die Masse keine Kraft, so sind beide Plattenabstände gleich.  Verschiebt sich allerdings die mittlere Elektrode, so ändert sich die Kapazität der beiden Kondensatoren:

$ C_1 = {{\epsilon_0 \cdot \epsilon_r \cdot A}\over {d_0 + d}}$, $ C_2 = {{\epsilon_0 \cdot \epsilon_r \cdot A}\over {d_0 - d}}$. Es gilt demnach $C_1(d_0+d) = C_2(d_0-d) $ und so kann die Auslenkung $d$ berechnet werden:

$$d= d_0 {{C_2-C_1}\over{C_2 +C_1}}.$$

 

Eichen des Sensors (Umrechnen der Messwerte in die Beschleunigung)

Liegt der Sensor flach (und ruhig) auf dem Tisch, so hat die Erdanziehungskraft (1g) nur einen Einfluß auf die Werte, die in z-Richtung gemessen werden. In x bzw. y-Richung wirken 0g. Man bestimmt den (maximalen) Wert in +z - Richtung und den (minimalen) Wert in -z -Richtung.

Beispiel (z-Achse) 
AusrichungMesswert
nach oben $+1g$ 620
nach unten $-1g$ 417

Damit erhalten wir eine Gerade $A_z = {2 \over 203} \cdot (z-417)-1$, um die Messwerte in die Beschleunigung in z - Richtung mit der Einheit g umzurechnen. 

Dasselbe macht man für die Beschleunigungen in x bzw. y-Richtung. Hier kann man sich zu nutze machen, dass die Beschleunigung in z-Richtung  Null sein muss, wenn man z.B. die x-Achse nach oben (oder unten) hält.

Anwednung: Berechnung des Rotationswinkels zur Erdoberfläche

Um mit Hilfe des Beschleunigungssensors den Neigungswinkel zur Erdoberfläche zu bestimmen, muss dieser in Ruhe sein!

Der Sensor wird um den Winkel  $\alpha$ um die y-Achse gedreht, dadurch ändert sich die Beschleunigung in die x bzw. z-Richtung. Es gilt $ \vec A_z = g \cdot \cos(\alpha)$ und $ -\vec A_x = g \cdot \sin(\alpha)$ und so:

$$\tan(\alpha) = {{g \cdot \sin(\alpha)} \over {g \cdot \cos(\alpha)}} = -\frac{A_x}{A_z},$$

$$ \alpha = \arctan \left(-\frac{A_x}{A_z}\right) $$

Arduino Quelltext

Quelltext

const int xpin = A3;                  
const int ypin = A4;                  
const int zpin = A5;     
 
void setup()
{
  Serial.begin(9600);
  // falls 3,3 V mit AREF verbunden
  analogReference(EXTERNAL);
}
 
void loop()
{
  int x=analogRead(xpin);
  int y=analogRead(ypin);
  int z=analogRead(zpin);
  
  //Umrechnungsformeln (Beispielhaft)
  double A_x = 0.00957*(x-403)-1;   
  double A_y = 0.009709*(y-397)-1;
  double A_z = 0.00985*(z-417)-1;
  
  // Gesamtbeschleunigung  (bei Ruhe 1g)
  double g =sqrt(A_x*A_x+A_y*A_y+A_z*A_z); 

  // Drehwinkel um die x-Achse im Gradmaß
  double x_drehung = (atan(-A_y/A_z))*(360/(2*PI)); 
  // Drehwinkel um die y-Achse im Gradmaß
  double y_drehung = (atan(-A_x/A_z))*(360/(2*PI)); 
  
  Serial.print(x_drehung);
  Serial.print("\t");
  Serial.print(y_drehung); 
  Serial.print("\t");
  Serial.print(g); 
  
  Serial.println();
  delay(500);
}

Visuelle Darstellung der Messdaten

Mit Processing kann man die Messwerte, die über den seriellen Port geschickt werden, schön darstellen. Processing wird in  JAVA geschrieben. Ein Tutorial findet sich z.B. hier . 

Wie man die Messwerte mit scratch darstellen kann wird im Kapitel scratch für arduino gezeigt.

Processing Quelltext

Processing Quelltext

// download von http://www.heise.de/ct/projekte/machmit/processing/wiki/ctDownloadProcessing
import processing.serial.*;

Serial port;
String buff = "";
int NEWLINE = 10;

// die letzten 128 Werte werden gespeichert
int[] xvalues = new int[128];
int[] yvalues = new int[128];
int[] zvalues = new int[128];

int xval, yval, zval, avx, avy, avz;
PFont font;

void setup()  
{
  size(512, 512);

  println("Available serial ports:");
  println(Serial.list());
  port = new Serial(this, Serial.list()[0], 9600);  
  font = loadFont("Verdana-12.vlw");
  textFont(font); 
}

void draw()
{
  background(0);

  avx = 0;
  avy = 0;
  avz = 0;

  stroke(255, 0, 0); // x ist rot
  for (int i = 0; i < 127; i++){
    line(i * 4, 512 - xvalues[i]/2, (i + 1) * 4, 512 - xvalues[i + 1]/2);
    avx = avx + xvalues[i];
  }
  
  stroke(0, 255, 0); // y ist grün
  for (int i = 0; i < 127; i++){
    line(i * 4, 512 - yvalues[i]/2, (i + 1) * 4, 512 - yvalues[i + 1]/2);
    avy = avy + yvalues[i];
  }
  
  stroke(0, 0, 255); // z ist blau
  for (int i = 0; i < 127; i++){
    line(i * 4, 512 - zvalues[i]/2, (i + 1) * 4, 512 - zvalues[i + 1]/2);
    avz = avz + zvalues[i];
  }

  fill (255, 0, 0);
  text("Durchschnitt x value (last 128): "+ avx/128, 10, 20);
  fill (0, 255, 0);
  text("Durchschnitt y value (last 128): "+ avy/128, 10, 40);
  fill (0, 0, 255);
  text("Durchschnitt z value (last 128): "+ avz/128, 10, 60);

  while (port.available() > 0)
    serialEvent(port.read());
}

void serialEvent(int serial)
{
  if (serial != NEWLINE) {
    buff += char(serial);
  } 
  else {
    if (buff.length() < 2) {
      buff = "";
      return;
    }
    buff = buff.substring(0, buff.length()-1);

    String bufs[] = buff.split(";");
    if (bufs.length != 3) {
      buff = "";
      return;
    }

    try {
      xval = Integer.parseInt(bufs[0]);
      yval = Integer.parseInt(bufs[1]);
      zval = Integer.parseInt(bufs[2]);
    }
    catch (NumberFormatException ex) {
      return;
    }
    buff = "";
    for (int i = 0; i < 127; i++)
      xvalues[i] = xvalues[i + 1];
    for (int i = 0; i < 127; i++)
      yvalues[i] = yvalues[i + 1];
    for (int i = 0; i < 127; i++)
      zvalues[i] = zvalues[i + 1];
    xvalues[127] = xval;
    yvalues[127] = yval;
    zvalues[127] = zval;
  }
}

Messwerte speichern

Mit Hilfe des XINTE Datenprotokollierung Shield v1. 0-Datenlogger kann man die Messwerte in einer Datei auf einer SD Karte abspeichern.

Messwerte in eine Datei schreiben Quelltext

ADXL auslesen und in Datei speichern

#include <SD.h>
const int chipSelect = 10;


const int xPin = A2;
const int yPin = A1;
const int zPin = A0;
 
 

void setup()
{
  Serial.begin(9600);
 


  Serial.print("Karte erkennen...");
  pinMode(10, OUTPUT);
  
  if (!SD.begin(chipSelect)) {
    Serial.println("Karte nicht erkannt.");
    return;
  }
  Serial.println("Karte OK.");
}

void loop()
{
  String DatenString = "";
  
  DatenString = String(analogRead(xPin));
  DatenString +=";";
  DatenString +=String(analogRead(yPin));
  DatenString +=";";
  DatenString +=String(analogRead(xPin));
  
  File dataFile = SD.open("ADXL.txt", FILE_WRITE);

  if (dataFile) {
    dataFile.println(DatenString);
    dataFile.close();
    Serial.println(DatenString);
  }  
  else {
    Serial.println("Kann Datei nicht öffnen");
  } 
}

Datenblatt

http://www.segor.de/dokumente/adxl335.pdf

daraus:

Empfindlichkeit bei  X_OUT, Y_OUT, Z_OUT  bei U = 3 V  300  mV/g

0 g Voltage at X_OUT, Y_OUT bei U = 3 V 1.35 V(Minimum)  1.5 V (typisch) 1.65 V (Maximum)
0 g Voltage at Z_OUT bei U = 3 V 1.2 V(Minimum) 1.5 V (typisch) 1.8 V(Maximum)