Crea sito

Progetto Memjet Urban Scooter con Arduino UNO

  • Schema Kymco 500
  • Montaggio A
  • Scooter Kymco 500
  • Montaggio B
  • Cruscotto Kymco 500
  • Sotto Sella Kymco

Come già anticipato questo progetto è nato dalla necessità di gestire la Centralina Memjet Urban del mio Scooter senza doverla impostare ogni volta (a scooter fermo) e ovviamente senza modificarla sia nei cablaggi che nella struttura.

Considerando anche un difetto dello scooter (almeno il mio) quello di avere l'orologio piccolo e inaffidabile, (se stacco la batteria perde l'ora...), ho integrato anche l'RTC con DS1307 nel circuito.

Vediamo quindi cosa comprende il progetto :

  • Controllo Servo Motori
  • Real Time Clock Dallas DS1307 (Data, Ora e Cronometro)
  • ADXL335B Accellerometro 3 Assi (Angolo di Piega)
  • LM335Z (Controllo Temperatura)

Per tutto quello che riguarda Arduino, sia l'Hardware che il Software e le librerie, il riferimento principale non può che essere http://arduino.cc/en/ .

Il progetto è ovviamente un insieme di applicazioni della MCU Atmel che trova nella rete tutte le spiegazioni più dettagliate, comunque cercherò, con parole semplici  e schemi, di rendere la più chiara possibile questa realizzazione nel caso qualcuno ne prenda alcune parti per integrarle in progetti propri.

Controllo Servo Motori

Knobb

La libreria Servo permette la completa gestione degli stessi e permette la trasformazione di angoli in segnali, senza bisogno di calcolare duty cycle e tempi.

Riporto  l'esempio preso da http://arduino.cc/en/Tutorial/Knob , molto semplice e allo stesso tempo completo dei comandi essenziali da usare.

Lo sketch riportato introduce anche l'uso della funzione map(value, fromLow, fromHigh, toLow, toHigh) che permette di trasformare un range di valori in un altro. Rimando ovviamente al sito ufficiale per tutti gli approfondimenti del caso. http://arduino.cc/en/Reference/Libraries

Exported from Notepad++
// Controlling a servo position using a potentiometer (variable resistor) // by Michal Rinott <http://people.interaction-ivrea.it/m.rinott> #include <Servo.h> Servo myservo; // creo l'oggetto servo per il suo controllo int potpin = 0; // pin analogico del potenziometro int val; // variabile che memorizza il valore letto void setup() { myservo.attach(9); // pin di Arduino dove è attaccato il servo } void loop() { val = analogRead(potpin); // legge in valori del potenziometro(escursione tra 0 e 1023) val = map(val, 0, 1023, 0, 179); // vengono ridotti per utilizzarli con il servo (escursione tra 0 e 180) myservo.write(val); // comando il servo con il valore letto delay(15); // aspetto che il servo esegua il comando }

DS1307 Real Time Clock

L'RTC con DS1307 richiede solo un quarzo esterno, la tipica batteria CR2032 e le resistenze di pull up come si può vedere dal datasheet, quindi si realizza su millefori senza problemi

Se invece non avete voglia di sbattimenti extra, trovate su ebay o comunque negli shop online di componentistica kit già predisposti su C.S.

Riporto comunque lo schema dei collegamenti che ho utilizzato sulla millefori per poi passare alla parte di sketch che si occupa della sua gestione.

Ecco il codice per inizializzare e poi leggere il DS1307.

Exported from Notepad++
//Includo la libreria per la //gestione del Bus I2C #include <Wire.h> void setup() { //Inizializzo la libreria Wire.begin(); //Aggancio il DS1307 al suo //indirizzo che è 0x68 Wire.beginTransmission(0x68); //il primo byte stabilisce il registro //iniziale da scrivere Wire.write((byte)0x00); //Inserisco Data e Ora Wire.write((byte)0x00); //1° byte SECONDI da 0x00 a 0x59 Wire.write((byte)0x40); //2° byte MINUTI da 0x00 a 0x59 Wire.write((byte)0x80 | 0x15); //3° byte ORE da 0x00 a 0x24 Wire.write((byte)0x02); //4° byte GIORNO della settimana da 0x01 a 0x07 Wire.write((byte)0x25); //5° byte GIORNO del mese da 0x00 a 0x31 Wire.write((byte)0x12); //6° byte MESE da 0x00 a 0x12 Wire.write((byte)0x12); //7° byte ANNO 0x00 a 0x99 Wire.endTransmission(); // In questo caso sono le 15:40.00 di Martedì 25 Dicembre 2012 }
Exported from Notepad++
void loop() { //Start dall'indirizzo 0x00 Wire.beginTransmission(0x68); Wire.write((byte)0x00); Wire.endTransmission(); //Richiedo 7 byte dal dispositivo con //indirizzo 0x68 Wire.requestFrom(0x68, 7); //Scrivo nelle Variabili le letture //dei registri in sequenza byte secondi = Wire.read(); byte minuti = Wire.read(); byte ora = Wire.read(); byte giorno_sett = Wire.read(); byte giorno_mese = Wire.read(); byte mese = Wire.read(); byte anno = Wire.read(); Serial.print("Orario corrente: "); Serial.print(ora, HEX); Serial.print(":"); Serial.print(minuti, HEX); Serial.print(":"); Serial.println(secondi, HEX); Serial.print("Giorno della settimana: "); Serial.println(giorno_sett, HEX); Serial.print("Data corrente: "); Serial.print(giorno_mese, HEX); Serial.print("/"); Serial.print(mese, HEX); Serial.print("/"); Serial.println(anno, HEX); Serial.println(); delay(1000); }

Per una maggiore chiarezza riporto la strutttura dei suoi registri interni che con il programma andiamo a gestire.La comunicazione tra Arduino e il DS1307 avviene quindi tramite bus I2c e la libreria wire semplifica e gestisce in modo completo il rapporto tra le due schede.

Accellerometro ADXL335 3 Assi +/- 3g

Accellerometro

L'accelerometro da me utilizzato è L' ADXL335 che "lavora" sui tre assi XYZ e fornisce una tensione proporzionale all'accellerazione nel range di +/- 3g.

Attenzione alla sua alimentazione che può variare da 1,8V (min) a 3,6V (max), quindi utilizzo la parte power di Arduino a 3,3 V.Non va alimentato a 5V !

 

Nel mio progetto viene utilizzato per visualizzare sul display l'angolo di piega dello scooter , inoltre impostando un rifermento viene segnalato il superamento della soglia con un allarme visivo e sonoro.

A breve importerò un video sul funzionamento, considerando che tutto il progetto è già montato e operativo sullo scooter da diversi mesi (circa 400km a settimana per lavoro), e a parte alcuni dettagli migliorabili fa quello per cui è stato pensato.

Exported from Notepad++
//Ingressi analogici di Arduino const int xPin = 0; const int yPin = 1; const int zPin = 2; //Valori massimo e minimo dell'accellerometro //utilizzato e quindi da modificabili se necessario int minVal = 265; int maxVal = 402; //Variabili che contengono il valore rilevato double x; double y; double z; void setup(){ Serial.begin(9600); } void loop(){ //Lettura dei valori di tensione fornito dall'ADXL335 int xRead = analogRead(xPin); int yRead = analogRead(yPin); int zRead = analogRead(zPin); //Conversione dei valori letti in gradi -90 to 90 //necessaria per poi utilizzare Atan2 int xAng = map(xRead, minVal, maxVal, -90, 90); int yAng = map(yRead, minVal, maxVal, -90, 90); int zAng = map(zRead, minVal, maxVal, -90, 90); //Calcolo e conversione con atan2 dei radianti //in gradi x = RAD_TO_DEG * (atan2(-yAng, -zAng) + PI); y = RAD_TO_DEG * (atan2(-xAng, -zAng) + PI); z = RAD_TO_DEG * (atan2(-yAng, -xAng) + PI); //Visualizzo i valori Serial.print("x: "); Serial.print(x); Serial.print(" | y: "); Serial.print(y); Serial.print(" | z: "); Serial.println(z); delay(100);

Sensore di Temperatura LM335

Nel datasheet viene indicata la formula che lega la tensione per una data temperatura in gradi Kelvin, con le opportune variazioni, in base alla tensione letta (tramite un ingresso analogico di Arduino ricaveremo la temperatura in gradi Celsius.

La formula fa riferimento ai gradi Kelvin, e a un valore di riferimento di 298.15°K (25°C) che produce in uscita 2.98Volt.

V_LM335 = V_25°C * Tx_°K / 298,15°K

Quindi nel nostro caso la temperatura incognita in kelvin sarà :

Tx_°K =  V_LM335 /(2,98V / 298,15°K)

a cui verranno sottratti 273,15 per ottenere i gradi centigradi.

  • LM335 Typ
  • LM335
  • LM335 Cal
  • LM335 Package

Ecco lo sketch relativo, si può anche visualizzare il valore letto sul pin di Arduino (cntAD) per avere direttamente la comparazione tensione - temperatura :

Exported from Notepad++
#include <LiquidCrystal.h> // Variabili Temperatura int cntAD = 0; float volt = 0; float gradiC = 0; void setup() { //Serial.begin(9600); lcd.begin(40, 2); // Set numero colonne e righe } void Temperatura() { cntAD = analogRead(3); volt = cntAD * 5.00 / 1023.0; // 0..5 volt gradiC = (volt /(2.98/298.15))-273.15; delay(100); lcd.setCursor(0, 0); lcd.print("Temperatura AMBIENTE : < "); lcd.setCursor(25, 0); lcd.print(gradiC); lcd.setCursor(30, 0); lcd.print(" > Gradi "); //Allarme se la temperatura non rientra nel range if ((gradiC > 25) or (gradiC < 1)) { tone(buzzer,500,50);} delay(100); }

Ricordiamo che la precisione dell' LM335 è di circa 0,5°C, più che sufficiente per indicarmi quanto freddo o caldo mi circonda; nel prossimo progetto utilizzeremo anche i Dallas 18B20 collegati in cascata su un unico bus che usano una libreria dedicata.

Programma Completo Memjet Scooter

Ricordo che nel listato trovate anche la gestione dei salvataggi in eprom dell'angolo di piega , la regolazione dell'orario, la funzione cronometro e la parte di pilotaggio dell'lcd.