Electric train hack proto

This will be a very quick post since there is nothing new on this project
.except maybe the use of openscad to do the design of the train structure.

Original goal is to have a small electric train running all over the office hanging on the celling. This is the prototype 😉

Train_proto

I simply buy an electric train on Amazon :

http://www.amazon.com/Bachmann-Trains-Thoroughbred-Ready–Scale/dp/B001RG7LDU/ref=sr_1_12?s=toys-and-games&ie=UTF8&qid=1437179429&sr=1-12

Then I rip it apart to understand how it works to be able to hack it.

Train principle

The train itself is very very stupid and is just some metal structure (pretty heavy by the way) with a motor.

Train_rip

The power for the motor comes directly from the rail through the wheels:

Train_wheel

The rails on the other side are smarter since there is a control panel to change the train speed/direction.

Rail_train

The principle is thus very simple…..The command panel generate a different tension in the rail to increase/decrease the speed. It can also invert the tension to go revert.

Hack it

I wanted several things:

  • Possibiility to control the train from phone
  • Train should works without a close circuit (in the office we only have one straigt way).

I decided to put the logic in the train rather than the rail. To do so I used an Arduino Micro (same as leonardo but smaller) with a motor controller and a BT receiver. There is nothing new here that I already done/explain in previous project except the motor controller.

The Bluetooth communication with an Android APP is the same software that the one used in this previous project : http://djynet.net/?p=639

The motor controller is the one of Sparkfun (HERE) and can control up to 2 motors. I used it to be able to change the motor rotation direction and speed (with PWM from arduino). This is indeed mandatory because the train will have to go in the 2 directions due to the linear rail circuit (one strait line).

The rails have now a constant tension of 12V from a AC/DC converter which power all the cards. The train is equipped with 2 sensors at front and rear. They are used to detect collision at the end of rail road and change the motor direction to go reverse

collision_sensor

The program is pretty simple since it just monitor collision sensor to change direction and serial bus for incoming Bluetooth message.

Finally I needed to put all that on the top of the train base with a nice 3D printed support. This was the good opportunity to try 3D printing. I done the design with OpenScad

Thus it might be the application you are looking for when you are planning to create 3D models of machine parts but pretty sure is not what you are looking for when you are more interested in creating computer-animated movies.

OpenSCAD is not an interactive modeller. Instead it is something like a 3D-compiler that reads in a script file that describes the object and renders the 3D model from this script file.

To sum up….you code your design and then compile it to generate the STL file 😉

I just created a basic shape with the place for the sensor at both end and then upload it on shapeways (a cloud 3D printing service).

train_3d_base

It fit perfectly the train and here is the final result once everything is mounted on it:

train_final

All the code (Arduino, Android, OpenScad) is available on my bitbucket account here.

Next step…..why not a camera on the train streaming live 😉

Bluetooth Arduino for moisture sensor

This WE I wanted to try BT communication with an Arduino…. To have a real project I decided to use a moisture sensor to detect from my phone if my green plant needs some water.

Global1

Global2

Arduino Board

To do so I bought a sparkfun BT module “Bluetooth Mate Silver” available following this direct link : https://www.sparkfun.com/products/12576

The moisture sensor is pretty standard : http://www.dfrobot.com/index.php?route=product/product&product_id=599#.U8JDQbE39b0

The connection to the BT module is pretty easy with Power (+3.3V, Gnd) and serial Data (Rx BT – Tx Leonardo and Tx BT – Rx Leonardo). As soon as the BT module is powered up it will be visible as a BT module.

2014-07-12-09-38-59

On the Arduino side I done a very simple program which will listen on the serial link established with the BT module. Once the Leonardo received a char ‘h’ it will read the humidity sensor value (analog read) and send it back on the BT link. Here is the code :

/*
Created by Charles Walker (charles.walker.37@gmail.com)
 Test program for bluetooth communication
 Tested with Arduino Leonardo and BT module Mate Silver (sparkfun)
 */

void setup()
{
  //USB Serial port
  Serial.begin(115200);
  //BT module serial port
  Serial1.begin(115200); 
}

void loop()
{
  delay(5000);
  if(Serial1.available())  
  {
    //We received something on BT module
    char aReceived;
    aReceived = (char)Serial1.read();
    Serial.print("Receveid from BT module :");
    Serial.println(aReceived);  

    // if we received a read humidity request
    if (aReceived=='h')
    {
      // Reading humidity
      unsigned int aHumidityValue;
      aHumidityValue=analogRead(0);
      Serial.print("Moisture Sensor Value:");
      Serial.println(aHumidityValue);
      // Sending it to the BT module
      Serial1.println(aHumidityValue);
    }
  }
  if(Serial.available())  
  {
    //We received something on USB serial line - We will send it to the BT module
    char aToBeSend;
    aToBeSend = (char)Serial.read();
    Serial.print("Going to send :");
    Serial.println(aToBeSend);

    //Sending it to the BT module
    Serial1.print(aToBeSend);
  }
}

The last version is available on bitbucket HERE.

The second part is the Android application which will be able to interact with the Arduino module through BT communication. Before starting coding it I wanted to verify that the Arduino part is working fine.

To do so I download a Arduino App able to communicate over BT. I tried few of them and the best one I find is :

https://play.google.com/store/apps/details?id=ptah.apps.bluetoothterminal

I installed it and then try sending some commands to the Leonardo board.

BT_Moisture_Test

The application properly connects to the BT module and then we are able to send some commands. The Leonardo only respond to the ‘h’ command which trig moisture read and send it back to the phone.

Android application

First step….. Fix android Studio Beta 0.8 issue….. See : http://djynet.net/?p=652
Android APP creation in a dedicated thread….. See : http://djynet.net/?p=658

Conclusion :

The results with the sensor in moist earth (or not) with the Arduino and Android output.

Moisture_Ardu

Andro_Moisture

The whole code for the project (Android and Arduino) is on my bitbucket account here.

EnOcean library example

Following my last article on EnOcean library for Arduino I received some email because the usage example was not good. Indeed I probably didn’t copy past the last version of code so I decided to do a new example (and also improve the library).

This time I will command 1 LED strip using an EnOcean button PTM210. A short click on the button will change the LED strip color to a random one. A long click (more than 2s) turns it off.

Here is the result:

The system requires a strip RGB led, an Arduino Leonardo, an EnOcean TCM 310 receiver and an EnOcean PTM210 emitter (button).

A made few modifications to my first EnOcean library by adding a new variable to check if a message were received on the TCM310. I also add a method to clean the “message” object. The EnOcean library is still available on my bitbucket repo (HERE)

The code is pretty simple. On each loop we check if a new message is available on the TCM310.

void loop() 
{
  delay(50); 
  _Msg.decode();
  if (_Msg.dataAvailable() == true)
  {
    actionTaker();
    _Msg.reset();
  }
}

If yes we will either start a timer if it is a button press or take an action if it is a button release. The action depend if the timer is finish or not (to determine if it is a long or short click).

void actionTaker()
{
  if (_Msg.getPayload() == 0x70)
  {
    Serial.println("The user push the button. Nothing to do appart starting the timer");
    _TimerExpire = false;
    MsTimer2::start(); // active Timer 2 
  }
  else if (_Msg.getPayload() == 0x00)
  {
    Serial.println("The user stop pushing the enocean button");
    if (_TimerExpire == true)
    {
      Serial.println("The user push was more than the timer (long push)");
      TurnOffLed();
      _NbClick=0;
    }
    else
    {
      Serial.println("The user push was quick (short push)");
      RandomLedColor();
      _NbClick=0;
    }
  }
  else
  {
    Serial.print("Received an unsupported command : ");
    Serial.println(_Msg.getPayload());
  }
}

There is also some extra function to determine a rand color and send it to the LED. The whole code is available on bitbucket (HERE)

Librarie EnOcean pour TCM 310 sur Arduino

Suite a mon article sur le dĂ©codeur EnOcean j’ai dĂ©cidĂ© de crĂ©er une libraire pour Arduino pour le TCM310.

Le code est extrĂȘmement simple avec une classe “EnOcean” reprenant les Ă©lĂ©ments de la trame envoyĂ© par le TCM310.

EnOceanMsg::EnOceanMsg()
{
  _dataLength1 = 0;
  _dataLength2 = 0;
  _optLength = 0;
  _packetType = 0;
  _headerCrc8 = 0;
  _org = 0;
  _payload = 0;
  _senderId1 = 0;
  _senderId2 = 0;
  _senderId3 = 0;
  _senderId4 = 0;
}

Cette classe possĂšde une mĂ©thode “decode” qui utilise la lib software de l’arduino pour dĂ©coder ce qui arrive sur l USART :

void EnOceanMsg::decode()
{
while(Serial1.available() > 0)
{
    //Serial.println("Decoding");
    uint8_t aChar = Serial1.read();
    switch(_pos) 
    {
        case 0:
        if (aChar == START_BYTE) 
        {
            _pos++;
            //Serial.println("START");
        }
        break;

        case 1:
        // length msb
        _dataLength1=aChar;
        _pos++;
        //Serial.print("length msb:");
        //Serial.println(_dataLength1, HEX);
        break;
...

La classe offre Ă©galement une mĂ©thode “pretty print” pour afficher ses Ă©lĂ©ments (et donc les informations reçu du TCM 310) :

void EnOceanMsg::prettyPrint()
{
Serial.println("Pretty print start");

Serial.print("length:");
char buf1[9];
sprintf(buf1, "%04x", getPacketLength());
Serial.println(buf1);
//Serial.println(getPacketLength());

Serial.print("Optional length:");
Serial.println(_optLength);

Serial.print("Packet type:0x");
Serial.println(_packetType, HEX);

La derniĂšre version du code de la librairie est disponible sur BitBucket :
https://bitbucket.org/charly37/arduino_enocean_lib

Voila un exemple d’utilisation de la lib avec mon interrupteur EnOcean :

#include 

EnOceanMsg aMsg;

void setup()
{
  //USB
  Serial.begin(9600);
  //Pin 0/1
  Serial1.begin(57600);
}

void loop()
{
  delay(500); 
  aMsg.decode();
  Serial.println("Working");
  if (aMsg.getPayload() == 0x50)
  {
    Serial.println("OKOK");
  }
}

Ce qui produira le résultat suivant sur le moniteur série :

Working
Working
Pretty print start
length:0007
Optional length:7
Packet type:0x1
ORG:0xF6
Payload:0x70
Sender Id:8ba977
Pretty print end
Working
Pretty print start
length:0007
Optional length:7
Packet type:0x1
ORG:0xF6
Payload:0x0
Sender Id:8ba977
Pretty print end
Working
Working

Capteur meteo terrasse

CrĂ©ation d’un nouveau “end device” pour la terrasse :
20130602_203639

Il est base sur une carte Arduino non officielle : Ultra mini dont j ai dĂ©jĂ  parle lors d article prĂ©cĂ©dant. C’est la seule carte arduino que je connais qui est designe pour consommer le moins de courant possible (Cf article prĂ©cĂ©dant) !

La carte consomme moins de 1mA en veille (et monte a 30 environ) lorsqu’elle passe a l Ă©tat actif pour rĂ©cupĂ©rer la tempĂ©rature, humiditĂ©, et luminositĂ©. Les donnĂ©es sont ensuite envoyĂ©es au systĂšme. GrĂące a ces nouvelles data j’ai pu supprimer la “crontab” des volets qui ete fixe a 21h00. Maintenant les volets se ferme quand la luminositĂ© extĂ©rieur est trop faible 😉

Le plus difficile a Ă©tĂ© de rĂ©duire la consommation de la carte (96mA a l origine avec une carte Arduino Leonardo) a un niveau acceptable pour que le chargeur solaire soit suffisant (1mA en veille et 30mA en Ă©mission pendant 5s toutes les 10 minutes). Tout les optimes pour la consomation de courant sont dĂ©jĂ  explique dans mon article sur la carte “Mini Ultra +”.

Smart tableau – nouveau End Device pour mon system domotique

J’ai dĂ©cidĂ© d’ajouter un nouveau « end device » dans le systĂšme pour pouvoir mesure/contrĂŽler certains Ă©lĂ©ments de la cuisine.

Cadre_avant

Les fonctions de ce nouveau « end device » sont :

  • DĂ©tection de personne (capteur PIR)
  • DĂ©tecteur de fumĂ©e (dĂ©montage d’un dĂ©tecteur de fumĂ©e du commerce)
  • Mesure TempĂ©rature et humiditĂ©

L’ensemble des capteurs est monte Ă  l’arriĂšre d’un cadre qui est pose dans la cuisine au-dessus des rangements. Le capteur de fumĂ©e est donc trĂšs prĂȘt du plafond pour ĂȘtre sur qu’il dĂ©tectera bien un incendie.

L’ensemble du montage communique par ZigBee avec le coordinateur. Ensuite le coordinateur transmet les infos au « brain » au travers d’une liaison sĂ©rie USB (exactement comme les autres devices).

Le « brain » python doit donc maintenant ĂȘtre capable de comprendre ce nouveau device pour, par exemple, prĂ©venir de la dĂ©tection d’un incendie.

Ceci est trÚs simple grùce au design du system domotique puisque le « détecteur incendie » correspond parfaitement à un device de type « interrupteur stable » et donc il suffit de rajouter dans le « brain » une nouvelle action pour cet interrupteur stable en particulier. On ajoute donc :

if ((aOneDevice.id == 2) and (aOneDevice.currentStatus=="unstable")):
 sendEmailFireDetected()

dans la boucle des détections évÚnements trigger par les interrupteurs stable :

#Step 1 : Verifier tous les detecteurs (interupteurs stables) pour voir si ils ont ete actives et prendre les actions correspondantes avant de les reset
        #Par exemple si le detecteur de fumee a ete active alors on va envoyer un mail 
        logging.info("Checking all possible event")
        for aOneDevice in iListOfDevice.registeredDevices:
            logging.debug("checking event : " + str(aOneDevice.id))
            if ((aOneDevice.id == 2) and (aOneDevice.currentStatus=="unstable")):
                sendEmailFireDetected()
            elif ((aOneDevice.id == 10) and (aOneDevice.currentStatus=="unstable")):
                self.PeopleDetectedEntree(iListOfDevice)
            elif ((aOneDevice.id == 9) and (aOneDevice.currentStatus=="unstable")):
                self.PeopleDetectedCharlesRoom(iListOfDevice)
            aOneDevice.reset()

Ensuite il ne reste plus qu’à crĂ©er la fonction « send fire detection » pour prĂ©venir l’utilisateur qu’un incendie a Ă©tĂ© dĂ©tectĂ©. Pour le moment on se contente d’envoyer un email mais dans l’avenir on peut simplement faire Ă©voluer cette action avec par exemple un appel automatique au pompier

L’envoie de l’email est assure par la fonction suivante :

def sendEmailFireDetected():
 '''Envoie email lors de la detection incendie'''
 logging.error("Envoi email detection incendie")
 # Define email addresses to use
 addr_to = Config["addr_to"]
 addr_from = Config["addr_from"]
 # Define SMTP email server details
 smtp_server = Config["smtp_server"]
 smtp_user = Config["smtp_user"]
 smtp_pass = Config["smtp_pass"]

 # Construct email
 expires = datetime.datetime.now()
 msg = MIMEText('Fire detected at ' + str(expires))
 msg['To'] = addr_to
 msg['From'] = addr_from
 msg['Subject'] = 'Fire alarm'

 # Send the message via an SMTP server
 s = smtplib.SMTP(smtp_server, 587)
 s.login(smtp_user,smtp_pass)
 s.sendmail(addr_from, addr_to, msg.as_string())
 s.quit()

CrĂ©ation d’un daemon python capable de communiquer avec le port USB et un socket

Actuellement quand je clique sur un lien qui nĂ©cessite l’envoie d’un message a un capteur dans l’appartement comme par exemple « actualiser la tempĂ©rature » :

ScreenShot001

Le site web envoie une requĂȘte AJAX qui appel un script python pour communiquer par USB depuis le RaspberryPi vers l’Arduino Leonardo. Le script monitor ensuite le port USB pour la rĂ©ponse de l’Arduino Leonardo pendant 10s pour rĂ©cupĂ©rer la rĂ©ponse du capteur et la transmettre au site web et Ă  l’utilisateur.

TemperatureRequestV1

Ce design fonctionne plutĂŽt bien mais bug de temps en temps quand plusieurs personne tentent de rafraichir la tempĂ©rature et l’humiditĂ© en mĂȘme temps car une rĂ©ponse « humidité » peut arriver avant une rĂ©ponse « tempĂ©rature » et les rĂ©ponses seront inverse. De plus cela ne me permet pas de mettre des capteurs  qui ne nĂ©cessite pas d’ĂȘtre appelĂ© pour envoyer une information tel qu’un dĂ©tecteur de fumĂ©e 😉
J’ai donc dĂ©cidĂ© de revoir le script python pour lui permettre de recevoir des infos de capteur a tout moment sans interaction avec l’utilisateur. Ce daemon doit cependant toujours ĂȘtre capable de recevoir les demandes des utilisateurs du site web

Le daemon est donc en constante attente soit de message provenant de l’Arduino Leonardo au travers du port USB, soit de message de l’utilisateur (site web) provenant d’un client lĂ©ger python au travers d’un socket rĂ©seau.

TemperatureRequestV2Server

Le monitoring simultanĂ© du port USB et d’un socket se fait grĂące au module python « select » qui est un appel direct Ă  la fonction « select » disponible sous linux. C’est le moyen le plus simple que j’ai trouvĂ© pour faire du multiplexing sur mes 2 entrĂ©es (port USB et socket). Le code est donc plutĂŽt simple puisque l’on attend juste que « select » nous donne la main pour tester quelle « entrĂ©e » a reçue quelque chose. En fonction de l’entrĂ©e on procĂ©der au traitement. VoilĂ  le code avec quelque commentaire pour mieux comprendre 😉

Un gros changement a Ă©galement eut lieu dans la chaine de rĂ©ponse puisque le process est maintenant asychrone. Il faut donc inclure plus d’information dans la rĂ©ponse tel que l’ID du capteur pour savoir a quoi correspond la valeur reçue sur le port USB. VoilĂ  un nouvel exemple de rĂ©ponse de l’Arduino  Leonardo
La rĂ©ponse comporte plusieurs champ/valeur tel que l’ID du capteur. Cet ID sera Ă©galement insĂ©rĂ© dans la DB.

Bonus :

Comme il m’arrive de temps en temps de redĂ©marrer mon Raspberry Pi et que le daemon n’est pas lance au dĂ©marrage le system pourrai ne plus fonctionner
.
J’ai donc lĂ©gĂšrement modifie mon client qui est appelĂ© par le serveur web pour dĂ©tecter si le daemon est bien dĂ©marrer sur le RaspberryPi. Si ce n’est pas le cas le Server se charge de dĂ©marrer le daemon. On ne pourra donc pas rĂ©pondre a la requĂȘte utilisateur mais au moins les suivantes fonctionneront bien.

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
    s.connect((HOST, PORT))
except:
    print("no server available")
    s.close()
    print("starting server")
    subprocess.call("python PythonWrapperWebArduinoUsbD.py", shell=True)
    #on va rester la a l infini

Exemple :

On lance le script python serveur avec les arguments tel qui l serait lancer par le site web a la rĂ©ception d’une requĂȘte client (les arguments utilisĂ©s simulant un Ping avec rĂ©ponse hardcode ‘456’ d’un capteur.

pi@raspberrypi ~/Usb_Arduino_Leonardo $ python PythonWrapperWebArduinoUsbS.py -s J -i 20 -o TOTO
no server available
starting server

Le client dĂ©tecte bien qu’il n y a pas de serveur et en lance donc un. Dans un autre terminal on relance le client

Client :

pi@raspberrypi ~/Usb_Arduino_Leonardo $ python PythonWrapperWebArduinoUsbS.py -s J -i 20 -o TOTO
Received 'MSG:J_ID:20_ORIGIN:TOTO'
pi@raspberrypi ~/Usb_Arduino_Leonardo $

Server :

pi@raspberrypi ~/Usb_Arduino_Leonardo $ python PythonWrapperWebArduinoUsbS.py -s J -i 20 -o TOTO
no server available
starting server
handle the server socket
handle all other sockets
input is : MSG:J_ID:20_ORIGIN:TOTO
Writting input to USB port and sending back to sender
Log line : DATE: 2013-03-11 21:02:08.518208 ORIGIN: TOTO CMD: J ID: 20
handle all other sockets
input is :
Closing socket

Le serveur Ă  bien reçu la demande du client et Ă  forwarder la demande a l’Arduino Leonardo par le port USB. Ensuite il a repris sa boucle et quelque secondes plus tard il a reçu la rĂ©ponse ‘456’ sur le port USB. La rĂ©ponse a Ă©tĂ© dĂ©codĂ© et stocke dans la DataBase pour ensuite ĂȘtre utilise sur le site Web.