Bike Bean mit einen aktivierbaren Bewegungsmelder ausstatten um per SMS gewarnt zu werden

Bike Bean mit einen aktivierbaren Bewegungsmelder ausstatten um per SMS gewarnt zu werden

Abermals auf Wunsch eines fahrradfahrenden Weltreisenden schreibe ich ein Tutorial wie man die Bike Bean Software und Hardware modifizieren kann um eine Warnung per SMS zu erhalten falls das abgestellte Fahrrad bewegt wird.

Ziel dieser Modifikation ist es, dass Bike Bean bereits den Diebstahlversuch meldet und idealerweise verhindert.

Schritt 1: Was benötigst du?

1 x Beschleunigungssensor (ADXL345)

1 x Taster z.B.: Folien-Taster

1 x Bike Bean

1 x USB zu TTL-Converter: (im Bike Bean Set enthalten)

Außerdem benötigst du ein paar geeignete Kabel und einen Lötkolben um die Bauteile mit der Bike Bean zu verbinden.

Schritt 2: Bauteile anschließen

Verbinde den Ground-Pin des Tasters mit Pin 13 der Bike Bean. Der VCC-Pin des Tasters kann an Pin 8 angeschlossen werden.

Verbinde den Beschleunigungssensor wie in folgender Grafik beschrieben:

Schritt 3: Software anpassen

Wie du die Firmware deiner Bike Bean anpassen kannst findest du hier beschrieben.

Folge den Anweisungen um deine Bike Bean mit deinem PC zu verbinden und ändere dann deinen Code.

Als Basis für die in diesem Tutorial modifizierte Firmware wird die Version 1.2 der Bike Bean Firmware genutzt. Am Ende dieses Tutorials findest du den kompletten Quellcode zum Download.

Zunächst müssen wir die Software Serial Bibliothek ändern, da diese die gleichen Interrupts nutzen möchte, die wir auch mit dem Taster nutzen werden. Dazu musst du die modifizierte Bibliothek ModifiedSWSerial.cpp & ModifiedSWSerial.h herunterladen und in den passenden Ordner legen. Unter Windows ist es in folgendem Ordner.

Dies sind die zwei Dateien, die eine Bibliothek definieren:

Die Standard-Bibliothek Wire.h kann über die Funktion in der Arduino Umgebung “Bibliotheken verwalten” eingefügt werden.

Die zusätzlichen Bibliotheken ModifiedSWSerial.h und Wire.h sind in Zeile 11 und 14 hinzugefügt.

#include <ModifiedSWSerial.h> 
#include <Wire.h>  

Neben den Änderungen der Bibliotheken muss die Initialisierung der genutzten Software Serials angepasst werden.

ModifiedSWSerial gsmSerial(PD6, PD5); //RX ,TX
ModifiedSWSerial wifiSerial(4, 17); //RX, TX

Außerdem sind ein paar zusätzliche Variablen notwendig:

float sensitivity = 0.2;                //higher less sensitive
float X_out, Y_out, Z_out;              //accelerometer values
float X_out_new, Y_out_new, Z_out_new;  //accelerometer comparison values
int alarm=0;                            //alarm indicator
boolean isaccelon = false;              //accelerometer on/off indicator
int buttoncount=0;                      //counts button hits
int ADXL345 = 0x53;                     //ADXL345 sensor I2C address

Mit der Variablen sensitivity kannst du die Sensität deines Beschleunigungssensors einstellen.

Im Setup müssen der Interrupt Pin 8 definiert werden und ein Ground-Pin für den Taster bereitgestellt werden:

void setup() {
  wdt_disable();  //recommended to do this in case of low probability event
  Serial.begin(9600);
  wifiOff();

  digitalWrite(8,HIGH); //Pin for button
  pciSetup(8);
  
  pinMode(13, OUTPUT); //ground pin for button
  digitalWrite(13, LOW);
}

In der Zeile 75 ist folgender Code hinzugekommen:

if(alarm==1 && mytelephonenumber != 0 && isaccelon==true){
    char *sendsmstext = sendsmstextarray; 
    memset(sendsmstextarray, NULL, 161);   
    strcat(sendsmstext, "ALARM"); 
    SendSMS(mytelephonenumber, sendsmstext); 
    isaccelon=false;
  }

Dieser Code schaut ob dein Fahrrad bewegt wurde (alarm = 1) und der Beschleunigungssensor überhaupt scharft geschaltet ist (isaccelon==true). Außerdem wird überprüft ob du eine Telefonnummer hinterlegt hast, da sonst keine Warnung verschickt werden kann.

Deine Telefonnummer hinterlegst du entweder mit dem SMS-Befehl “Warningnumer” oder schreibst sie direkt in den Code in Zeile 20:

char mytelephonenumberarray[20] = "+49XXXXXXXXXXXX";

Dann wird eine SMS mit dem Text “Alarm” verschickt und der Beschleunigungssensor ausgestellt, damit nur eine Warnungen verschickt wird und nicht unzählige.

Ab Zeile 398 werden einige Modifikationen notwendig:

  X_out_new=0;
  Y_out_new=0;
  Z_out_new=0;
  
  for (int counter2 = 0; counter2 < (interval * (3600/2)); counter2++) { //sleep X h
   delayWDT(WDTO_2S);   // deep sleep
    if (digitalRead(8)==LOW){ //required for button interrupt
      delay(10000);
    }
    if(isaccelon == true){
      startaccel();
      X_out = X_out_new;
      X_out_new = readaccel('x');
      Y_out = Y_out_new;
      Y_out_new = readaccel('y');
      Z_out = Z_out_new;
      Z_out_new = readaccel('z');
      endaccel();
      
      if(abs(X_out-X_out_new) > sensitivity && X_out != 0 || abs(Y_out-Y_out_new) > sensitivity && Y_out != 0 || abs(Z_out-Z_out_new) > sensitivity && Z_out != 0){       
       alarm = 1;
       break;    
      }
    }

Zunächst setzen wir die Anfangswerte X_out_new, y_out_new und Z_out_new auf 0. Dann startet die übliche Tiefschlafschleife der Bike Bean. Falls der Taster gedrückt wird, wird aber eine Pause von 10 Sekunden eingelegt mit delay(10000); um zu überprüfen ob weitere Tastendrücke kommen. Außerdem wird überprüft ob der Beschleunigungssensor angeschaltet ist mit if(isaccelon==true). Wenn dem so ist werden die Beschleunigungswerte alle ~2 Sekunden ausgelesen und verglichen.

Sollten die verglichenen Werte um einen Betrag der größer als die eingestellte Sensitivität (sensitivity) ist abweichen, wird die Tiefschlafschleife verlassen um das GSM-Modul anzuschalten und eine Warnung zu verschicken.

In den oben erwähnten Codes haben wir einige neue Funktionen verwendet auf die wir nun eingehen.

Mit dieser Funktion kann ein Pin der Bike Bean zum Interrupt Pin konfiguriert werden.

void pciSetup(byte pin){
    *digitalPinToPCMSK(pin) |= bit (digitalPinToPCMSKbit(pin));  // enable pin
    PCIFR  |= bit (digitalPinToPCICRbit(pin)); // clear any outstanding interrupt
    PCICR  |= bit (digitalPinToPCICRbit(pin)); // enable interrupt for the group
}

Falls ein Interrupt auf diesem Pin erfolgt wird folgende Funktion ausgeführt:

ISR (PCINT0_vect){ // pin change interrupt for D8 to D13  
  static unsigned long last_interrupt_time = 0;
  unsigned long interrupt_time = millis();

  if(interrupt_time-last_interrupt_time > 400){ //debouncing button
    if(interrupt_time-last_interrupt_time > 5000){ //checks button presses within the last 5 seconds
      buttoncount=1;  
    }else{
      buttoncount++;
      if(buttoncount == 2){
        isaccelon = true; 
      }else
      if(buttoncount == 3){
        isaccelon = false; 
        buttoncount=0;  
      }
    }
  }
  last_interrupt_time = interrupt_time;
}

Diese Funktion überprüft wie oft der Taster gedrückt wird und in welcher Zeit. Mit zwei mal drücken innerhalb von 5 Sekunden wird der Beschleunigungssensor scharf geschaltet und mit drei mal drücken innerhalb von 5 Sekunden wird dieser ausgestellt. Zum entprellen des Tasters wird überprüft ob der letzte Tastendruck > 400 Millisekunden zurück liegt.

Der Beschleunigungssensor wird mit folgender Funktion bei Bedarf gestartet:

void startaccel(){
  
  pinMode(11, OUTPUT);
  digitalWrite(11, LOW); //Ground pin for accelerometer
  pinMode(12, OUTPUT);
  digitalWrite(12, HIGH); //VCC pin for accelerometer
  delay(100); //wait for startup

  Wire.begin(); // Initiate the Wire library
  // Set ADXL345 in measuring mode
  Wire.beginTransmission(ADXL345); // Start communicating with the device 
  Wire.write(0x2D); // Access/ talk to POWER_CTL Register - 0x2D
  // Enable measurement
  Wire.write(8); // (8dec -> 0000 1000 binary) Bit D3 High for measuring enable 
  Wire.endTransmission();
  delay(10);
}

Zum auslesen der Werte des Beschleunigungssensors dient diese Funktion:

float readaccel(char axis){ 
  float X_out1, Y_out1, Z_out1;
  // === Read acceleromter data === //
  Wire.beginTransmission(ADXL345);
  Wire.write(0x32); // Start with register 0x32 (ACCEL_XOUT_H)
  Wire.endTransmission(false);
  Wire.requestFrom(ADXL345, 6, true); // Read 6 registers total, each axis value is stored in 2 registers
  X_out1 = ( Wire.read()| Wire.read() << 8); // X-axis value
  X_out1 = X_out1/256; //For a range of +-2g, we need to divide the raw values by 256, according to the datasheet
  Y_out1 = ( Wire.read()| Wire.read() << 8); // Y-axis value
  Y_out1 = Y_out1/256;
  Z_out1 = ( Wire.read()| Wire.read() << 8); // Z-axis value
  Z_out1 = Z_out1/256;

  if(axis=='x'){
    return X_out1;
  }else
  if(axis=='y'){
    return Y_out1;
  }else
  if(axis=='z'){
    return Z_out1; 
  }
}

Wenn der Beschleunigungssensor nicht mehr benötigt wird, wird er wieder abgestellt:

void endaccel(){
  pinMode(11, INPUT);
  pinMode(12, INPUT);
}

Da wir zum fehlerfreien Funktionieren der Software ca. 350 Bytes Ram benötigen, müssen wir nun wieder etwas Platz schaffen.

Dazu kannst du z.B. Interval-Funktionen auskommentieren, die für dich eher weniger relevant sind. Im unteren Beispiel haben wir int4 und int8 auskommentiert

       /* if((strcasestr(checksmstext, "int4") != NULL && strlen(checksmstext) == 4) || (strcasestr(checksmstext, "int 4") != NULL && strlen(checksmstext) == 5)){
          interval = 4;
          char *sendernumber = SenderNumber(i);          
          char *sendsmstext = sendsmstextarray; 
          memset(sendsmstextarray, NULL, 161);
          strcat(sendsmstext, "GSM will be switched on every 4 hours.\nBattery Status: ");
          char battpercentage[3] = ""; 
          itoa(battpercent,battpercentage,10); 
          strcat(sendsmstext, battpercentage);
          strcat(sendsmstext, "%");
          SendSMS(sendernumber, sendsmstext);          
          free(sendernumber);
          DeleteSMS(i);   
        }else
        if((strcasestr(checksmstext, "int8") != NULL && strlen(checksmstext) == 4) || (strcasestr(checksmstext, "int 8") != NULL && strlen(checksmstext) == 5)){
          interval = 8;
          char *sendernumber = SenderNumber(i);          
          char *sendsmstext = sendsmstextarray; 
          memset(sendsmstextarray, NULL, 161);
          strcat(sendsmstext, "GSM will be switched on every 8 hours.\nBattery Status: ");
          char battpercentage[3] = ""; 
          itoa(battpercent,battpercentage,10); 
          strcat(sendsmstext, battpercentage);
          strcat(sendsmstext, "%");
          SendSMS(sendernumber, sendsmstext);          
          free(sendernumber);
          DeleteSMS(i); 
        }else */

Ob du genug Ram für deine Software freigelegt hast siehst du wenn du dein Programm kompelierst. In folgendem Fall sind noch 370 Bytes frei. Dies würde ausreichen.

Zu guter Letzt das komplette Programm zum Herunterladen. In diesem Programm ist die Änderung aus dem vorhergehenden Tutorial (Alarm ertönen lassen per SMS) ebenfalls enthalten.

Schritt 4: Fertig!

Folgendes hast du gelernt:

  • wie du den Code deiner Bike Bean anpassen kannst
  • wie du Bibliotheken einfügen kannst und Interrupts nutzt
  • wie du einen Beschleunigungssensor und Taster anschließt

Viel Spaß beim Basteln!