PARCO
PARCO | |
Poor Arduino Radioio COmunication un trasmettitore low power "parco" nei consumi, quasi "compatibile" bluetooth 4.0. |
Da dove nasce il progetto?
Dalla necessità di avere un sistema per leggere sensori con un sistema
- a basso consumo, alimentabile a batteria
- con costi ridotti
- wireless
Che cosa non si riesce a fare?
- una trasmissione bluetooth 4 vera e propria
- trovare board già completamente assemblate
- tramettere più di pochi byte per volta
- rendere sicura la comunicazione
Teoria
- Qualche info su Bluetooth 4, anche detto bluetooth low energy.
Low energy è la parola chiave da cui ho iniziato a cercare. Purtroppo il protocollo è complesso e le periferiche costose e difficili da programmare. Altro punto a favore di ble è che sono ammessi pacchetti broadcast cioè senza necessità di accoppiare i devices. Wikipedia
- Ho trovato questa interessante pagina che spiega come un modulo nrF2401+ possa essere utilizzato per trasmettere semplici annunci in formato bluetooth 4.0.
La potenza di questi moduli è minima, e più di questo non riescono a fare, ma è possibile usare il nome con cui si annuncia il nostro nodo per tasmettere alcuni byte. Blog dmitry.gr
- Sui commenti in fondo alla pagina segnalata sopra, qualcuno ha anche provveduto a creare una libreria per Arduino. BTLE Arduino library
- Per quanto riguarda arduino è necessario ridurre al minimo i consumi, quindi solo una scheda minimale come Arduino pro mini con alimentazione a 3.3V (e clock a 8Mhz) e utilizzo di sleep mode.
Codice Arduino
E' un assemblaggio di parti di codice presi dagli esempi della libreria con qualche piccolo adattamento per ridurre i consumi mandando il micro in sleep. La trasmissione avviene ogni 8 secondi circa, è adatta per sensori che misurano grandezze che hanno variazioni lente nel tempo. E' anche possibile disabilitare lo sleep se il "nodo" non ha necessità di risparmio energetico.
#include <SPI.h>
#include <RF24.h>
#include <BTLE.h>
#include <stdio.h>
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <avr/power.h>
#include <avr/wdt.h>
RF24 radio(8,7); //pin D8 -> CE ---- pin D7 -> CSN
BTLE btle(&radio);
char buffer[14] = "";
char fix[7] = "acqua";
int x=0;
int force;
int batt;
int trasmetti=1;
//Questa funzione mette il microcontrollore in modalità basso consumo per permettere una alimentazione a batterie
void enterSleep(void)
{
set_sleep_mode(SLEEP_MODE_PWR_DOWN); /* EDIT: could also use SLEEP_MODE_PWR_DOWN for lowest power consumption. */
sleep_enable(); // Abilita la modalità basso consumo
sleep_mode(); /* Now enter sleep mode. */
/* The program will continue from here after the WDT timeout*/
sleep_disable(); /* First thing to do is disable sleep. */
/* Re-enable the peripherals. */
power_all_enable();
}
//Gestione del watch dog timer, il micro viene settato per essere risvegliato dal watch dog timer ogni 8 secondi
ISR(WDT_vect)
{
sleep_disable(); //Disable Sleep on Wakeup, quando si verifica l'interrupt del watchdog
trasmetti=1; //setta la variabile trasmetti ad 1 per indicare che il micro è stato risvegliato e che è necessario trasmettere
}
void setup() {
sleep_disable(); //Disabilita la modalità sleep durante il boot
power_all_enable(); //Abilita tutte le periferiche
analogReference(INTERNAL); //Configurazione della tensione di rifermento per la lettura dei sensori analogici
randomSeed(analogRead(3)); //???
Serial.begin(9600);
while (!Serial) {
}
Serial.println("Arduino BTLE"); //Notifica su porta seriale il boot, serve anche come debug per vedere quando il micro è attivo senza avere collegato il pc.
//Settaggio variabili per modalità basso consumo
MCUSR &= ~(1<<WDRF); /*Clear the reset flag. */
WDTCSR |= (1<<WDCE) | (1<<WDE); /*In order to change WDE or the prescaler, we need to set WDCE (This will allow updates for 4 clock cycles). */
WDTCSR = 1<<WDP0 | 1<<WDP3; /* 8.0 seconds */
/* set new watchdog timeout prescaler value */
WDTCSR = 1<<WDP2; /*WDT interrupt every 250 milliseconds */
WDTCSR |= _BV(WDIE); /*Enable the WD interrupt (note no reset). */
//sei();
}
void loop() {
if (trasmetti==1) { //Verifica se è necessario tramettere
btle.begin(buffer); //inizia la trasmissione btle
btle.advertise(0,0);
Serial.print(" ");
btle.hopChannel();
//pinMode(10, OUTPUT);
digitalWrite(10, HIGH); // per ridurre i consumi, il sensore resistivo è collegato all'uscita di un pin che viene attivato alto solo prima di iniziare la misura
batt=analogRead(A1); // leggo la tensione della batteria per trasmetterla e permettere il monitoraggio della carica
force=analogRead(A7); // leggo il sensore di forza resistivo
digitalRead(10); // disabilito l'alimentazione del sensore resistivo
sprintf(buffer,"%3u%s% 4u",batt, fix,force); // creo la stringa con i dati da trasmettere ---- ATTENZIONE il buffer ha una dimensione limitata a 13 caratteri se la stringa è più lunga non viene trasmesso nulla!!!!!
Serial.println(buffer); // trasmetto la stringa su seriale, utile anche per un debug visivo quando il sensore è in posizione
// buffer[7]++;
trasmetti=0; // Azzeramento variabile trasmetti dopo che la trasmissione è avvenuta
//Serial.println("enter sleep");
radio.powerDown(); // Spengo il modulo radio
sleep_enable(); // Enable Sleep Mode del micro
enterSleep(); // Sleep
}
else {
sleep_enable(); // Se non è ora di trasmettere ..... Enable Sleep Mode
enterSleep();
}
}
Schema
Software pc
Attenzione il pc deve avere una periferica compatibile con bluetooth 4.0, i vecchi pc ne sono sprovvisti. Ho visto in vendita chiavette usb, ma non le ho testate.
L'ho scritto in python, ma sono sicuro sia migliorabile.
#!/usr/bin/python
import os
import subprocess
parole = subprocess.check_output("/bin/hciconfig hci0 down", shell=True)
parole = subprocess.check_output("/bin/hciconfig hci0 up", shell=True)
parole = subprocess.check_output("/usr/bin/timeout -s SIGINT 60s /usr/bin/hcitool lescan --duplicates | grep dist", shell=True)
#parole="15:01:13:18:22:37 874dist.5167"
print "Parole:" + str(parole)
if parole != 2 :
indirizzo=parole[:17]
print "Indirizzo: "
print indirizzo
print "Liv batteria: "
liv_batteria=parole[18:21]
print liv_batteria
int_liv_batteria=int(liv_batteria)
str_liv_batteria=liv_batteria
print "liv_batteria"
print int_liv_batteria
print "sensore:"
int_sensore=int(parole[26:30])
str_sensore=parole[26:30]
print int_sensore
Ricevitore con Arduino
Basta guardare negli esempi della libreria FLOE
Debug
Per chi ha un telefonino con interfaccia bluetooth 4 è possibile fare un debug usando l'app Nrf Master di Nordic il produttore del chio radio.
Il mio nodo PARCO si chiama acqua, la batteria è carica a 943/1023 nella prima schermata e 965/1023 nella seconda.
PARCO è quel trattino rosso che si vede nella figura centrale, anche se trasmette circa ogni 8 secondi l'app non riesce a intercettare tutti i messaggi.
Nella prima figura il sensore analogico sta leggendo 0 (è un sensore di forza), nell'ultima legge 1023 perchè sto premendo sul sensore.
Test sul campo
Ho testato un paio di questi sensori per diversi mesi usando batterie alcaline e la durata è estremamente interessante siamo nell'ordine di qualche mese.
E' necessario rimuovere il led di alimentazione sulla board Arduino.
Riferimenti
- dmitry.gr
- BTLE floe
- Bluetooth low-energy temperature beacon using the nRF24L01: cheap and compatible with existing smartphone apps! un progetto molto simile
[Category:Progetti]