Motivace :
Tchán léta jezdí Corsičkou a letos nastala štrapác, tachometr vypověděl službu, rafička splaskla k nule a hotovo. Pokusy nahradit čidlo v bloku motoru opakovaně selhaly a tak nastoupila alternativa satelitního měření rychlosti a analogového zobrazení aktuální rychlosti na tachometru. Vzorkování rychlosti v rozsahu 1 ~ 5 Hz bezpečně vyhoví potřebám analogového sledovače a postačí i bez nutnosti měnit uloženou defaultní konfiguraci GPS přijímače u-blox Neo-6M. Prototypové řešení volně zobrazuje aktuálně poslední přečtený údaj o rychlosti a tento pasivní mód je možné dále rozšiřovat zařazením aktivního filtru a vyhlazováním údajů pomocí modelovaného systému druhého řádu ( rychlost, zrychlení ).
obrázek
BoM ( Bill-of-Material ) :
1x mikrokontrolér Arduino Nano, klon CH340 (+5V)
1x přijímač GPS u-blox Neo-6M (+5V)
1x zobrazovací tachometr na bázi servomotoru SG90 (+5V)
1x USB-napaječ z palubní zásuvky (+5V)
1x USB-USB kabel napájení desky a přijímače GPS
1x sada propojovacích kabelů
Použité knihovny :- standardní knihovna Arduino IDE SoftwareSerial- standardní knihovna Arduino IDE Servo- standardní knihovna Arduino IDE TinyGPS++ viz: [file:TinyGPSPlus-1.0.2b.zip]Zdrojový kód :/* ARDUINO NANO [doc:https://dratek.cz/arduino/1069-eses-klon-arduino-nano-ch340.html]
Rx_DATA from u-Blox GPS-6M [doc:https://web.archive.org/web/20200610071942/https://www.u-blox.com/sites/default/files/products/documents/u-blox6_ReceiverDescrProtSpec_(GPS.G6-SW-10018)_Public.pdf]
-----+5V-> o-Vcc_GPS-6M [+ https://dratek.cz/arduino/1510-gps-neo-6m-gyneo6mv2-modul-s-antenou.html]
---TxPin-> o--Rx_GPS-6M
o-GND_GPS-6M
PWM_out to SERVO SG90 [doc:https://www.peckamodel.cz/jix-sg90-1-9g-mini-servo-sg90]
servoPin-> o--------SG90-PWM-(orange/yellow)--
-----+5V-> o--------SG90-Vcc-(red)------------
-----GND-> o--------SG90-GND-(brown)---------- */
//-----------------------------------------------------------
#include <TinyGPS++.h> // GPS toolkit used for NMEA-messages decodes, ref.[doc:Pg.63/210]
#include <Servo.h> // SERVO toolkit used to drive SG90
#include <SoftwareSerial.h> // UART RS-232 from the GPS-6M device
//-----------------------------------------------------------
#define GPSBaud 9600 // UART GPS-6M device default port speed is 9600-8-1-none [doc:Pg.7/210]
#define RxPin 2 // UART [2]_Rx Rx_GPS-6M
#define servoPin 9 // PWM [9]_PWM-----> SERVO-SG90_PWM_signal_IN
#define servoOnExit 0 //
//-----------------------------------------------------------
TinyGPSPlus gps; // new TinyGPS++ object for DECODEs
SoftwareSerial gpsSerial( RxPin, TxPin ); // new SERIAL instance for connection to the u-blox GPS-6M device
Servo meTachometroveSERVO; // new SERVO instance
int servoKMH = 0; // new int-variable to store GPS-reported speed [km/h].. [ToDo] as aRotatingBUFFER[3] in a 2nd-Order PDE speed-approximator
//-----------------------------------------------------------
void setup() { Serial.begin( 9600 ); // Start the Arduino hardware TTY port at 9600 baud
gpsSerial.begin( GPSBaud ); // Start the software SERIAL port at the GPS's baud (u-blox default value [fine for serving at about ~1 Hz GPS update messages] )
meTachometroveSERVO.attach( servoPin ); // Set the Arduino hardware PIN[servoPIN] dedicated to PWM driving SG90-servo
}
//-----------------------------------------------------------
void loop() {
while ( gpsSerial.available() > 0 ) // every time a new sentence is correctly encoded
if ( gps.encode( gpsSerial.read() ) ) { // READ it
displayDATA(); // TTY report [via USB to PC-host, if present] .... [ToDo] could be removed for a headless, production code
if ( gps.speed.isValid() ) update(); // TEST / UPD if .isValid() ...................... [ToDo] could be extended with a 2nd-Order PDE speed-approximator
meTachometroveSERVO.write( servoKMH ); // SET SG90-servo ( Corsa will never fly > 140 )... [ToDo] could be constrain()-fused for non-Corsa vehicles like UL-s
readGpsWhileInDELAY( 800 ); // WAIT read-feeding the gps-object for about 800 [ms] (ref. about the 1 Hz GPS-update)
}
//FUSE/////////////////////////------------------------------------------------------------------------------------- FUSE
if ( millis() > 5000 // soft-timeout 5[s] ~ if 5000 milliseconds pass and there are no characters coming in
& gps.charsProcessed() < 10 ) { // and too few CHARs came
Serial.println("No GPS detected"); // show "No GPS detected" on TTY port [via USB to PC, if present]
meTachometroveSERVO.write( servoOnExit ); // SET
delay( 1000 ); //
meTachometroveSERVO.detach(); // fuse SERVO out
while ( true ); // _______________________________________________________________________________________________________________ FOREVER _EndOfGame_STATE_LOCKOUT__
}
}
//-----------------------------------------------------------
static void update() { // UPD if .isValid() ............................ [ToDo] could be extended with a 2nd-Order PDE speed-approximator
servoKMH = map( (int)gps.speed.kmph(), // map int( .kmph() )
0, // mapFromLo ~ 0 km/h ....... (? dead zone around a walking speed ? :o)
160, // mapFromHi ~ 160 km/h ....... (a speed Opel Corsa ought never get ;)
4, // mapToLo ~ 4 of 180 steps
176 // mapToHi ~ 176 of 180 steps
); //
}
//-----------------------------------------------------------
static void displayDATA() { Serial.println();
Serial.println();
if ( gps.location.isValid() ) { Serial.print( "Latitude: " ); Serial.println( gps.location.lat(), 6 );
Serial.print( "Longitude: " ); Serial.println( gps.location.lng(), 6 );
Serial.print( "Altitude: " ); Serial.println( gps.altitude.meters() );
}
else Serial.println( "Location: Not Available" );
if ( gps.date.isValid() ) { Serial.print( "Date: " ); Serial.print( gps.date.month() ); Serial.print( "/" );
Serial.print( gps.date.day() ); Serial.print( "/" );
Serial.println( gps.date.year() );
}
else Serial.println( "Date: Not Available" );
if ( gps.time.isValid() ) { Serial.print( "Time: " );
if ( gps.time.hour() < 10 ) Serial.print( F( "0" ) );
Serial.print( gps.time.hour() ); Serial.print( ":" );
if ( gps.time.minute() < 10 ) Serial.print( F( "0" ) );
Serial.print( gps.time.minute() ); Serial.print( ":" );
if ( gps.time.second() < 10 ) Serial.print( F( "0" ) );
Serial.print( gps.time.second() ); Serial.print( "." );
if ( gps.time.centisecond() < 10 ) Serial.print( F( "0" ) );
Serial.println( gps.time.centisecond() );
}
else Serial.println( "Time: Not Available" );
}
//-----------------------------------------------------------
static void readGpsWhileInDELAY( unsigned long ms ) {
unsigned long start = millis();
do { while ( gpsSerial.available() ) gps.encode( gpsSerial.read() );
} while ( millis() - start < ms );
}
a