ODROID-GO is one of those small versatile extensible systems with which, given some imagination, you can create very useful and interesting projects. Here is one such project, that integrates a GPS sensor, to display GPS maps on an ODROID-GO.
The source code can be obtained from git repo: https://github.com/ripper121/OdroidGoOSMGPSOffline
The needed firmware can be fetched from this location: https://goo.gl/PgYF6C
The key menu is as follows:
- JoyPad = Move around
- A/B = Zoom in/out (Zoom Level goes from 5-16, depending on which tile zoom levels you have)
- Select / Start = Brightness
- Menu = Reset Movement
Generate tiles
As expected, the design limitations of the ODROID-GO do not permit live maps. So a map would have to prefetched and stored for later use. Tiles are essentially these offline maps.
Tiles can be downloaded on MS Windows system using the TileDownloader.exe application from: https://bit.ly/2HDsLRh (EDITOR: google’s url shortener does not work for this link)
The single-line command (replace coordinates specific to your location) to create a tile and fetch it:
> TileDownloader.exe -URL \https://a.tile.openstreetmap.org/${z}/${x}/${y}.png -z 5 -left -0.489 -botton 51.28 -right 0.236 -top 51.686Where the following options can be specified:
- -URL : TileServer
- -z : Zoom level
and the bounding box limits are:
- -left : min-longitude
- -bottom : min-latitude
- -right : max-longitude
- -top : max-latitude
In some regions, a comma ‘,’ may be the used instead of the period ‘.’, for the bounding box values.
Other tile servers at the following link can be used: https://wiki.openstreetmap.org/wiki/Tile_servers
Additional tiles can be obtained from: https://goo.gl/DRusXL
The offline maps can also be stored on an SDCard as seen here:
It uses a Zoom Level from 5 to 14, with the Position marker as the red circle.
This "scroll around" is a manipulation of the GPS Coordinates via the JoyStick. Following are the steps to generate tiles (offline Map) for your area:
- 1. Open Maperitive.exe (http://maperitive.net/)
- 2. Move the map to your favorite position
- 3. MAP->Set Geometry Bounds
- 4. MAP->Set Printing Bounds
Now the area of the map you want to Export is set.
- 5. TOOLS-> Generate Tiles (this can take some time, depending on the resolution of the Zoom Level)
- 6. Now you will find some PNG files in the Maperitive /tiles folder
- 8. Open Flexxi.exe (https://sourceforge.net/projects/flexxi-image-resizer/)
- 9. Import the Tiles Folder
- 10. Resize the Image to 240x240 px (best Fit for GO Screen)
- 11. Convert to JPG Files
- 12. Save
- 13. Now you have your tiles in the correct size and format
- 14. Copy the "TILES" (all Uppercase) folder to the root directory of your SD card
Open Arduino IDE and Flash the Code to your GO. This is the Arduino Code:
#include #define DISPLAY_WIDTH 320 #define DISPLAY_HEIGHT 240 #define TILE_SIZE 240 bool firstRun = true; double zoom = 10; double lat_rad = 50.8225313, lon_deg = 12.7508936; double tileX = 0, tileY = 0; double old_lat_rad = 0, old_lon_deg = 0; double old_zoom = 0; double old_tileY = 0, old_tileX = 0; uint8_t brightness = 127; void setup() { // put your setup code here, to run once: Serial.begin(115200); GO.begin(); GO.battery.setProtection(true); GO.lcd.clear(); GO.lcd.setCursor(0, 0); if (!SD.begin()) { GO.lcd.println("Card Mount Failed"); Serial.println("Card Mount Failed"); return; } uint8_t cardType = SD.cardType(); if (cardType == CARD_NONE) { GO.lcd.println("No SD card attached"); Serial.println("No SD card attached"); return; } Serial.print("SD Card Type: "); if (cardType == CARD_MMC) { GO.lcd.println("MMC"); Serial.println("MMC"); } else if (cardType == CARD_SD) { GO.lcd.println("SDSC"); Serial.println("SDSC"); } else if (cardType == CARD_SDHC) { GO.lcd.println("SDHC"); Serial.println("SDHC"); } else { GO.lcd.println("UNKNOWN"); Serial.println("UNKNOWN"); } uint64_t cardSize = SD.cardSize() / (1024 * 1024); Serial.printf("SD Card Size: %lluMB\n", cardSize); GO.lcd.printf("SD Card Size: %lluMB\n", cardSize); delay(3000); GO.lcd.clear(); GO.lcd.setCursor(0, 0); } //setBrightness(uint8_t brightness), void loop() { GO.update(); if (GO.JOY_X.isAxisPressed() == 1) { lon_deg += 0.0001; delay(10); } if (GO.JOY_X.isAxisPressed() == 2) { lon_deg -= 0.0001; delay(10); } if (GO.JOY_Y.isAxisPressed() == 2) { lat_rad += 0.0001; delay(10); } if (GO.JOY_Y.isAxisPressed() == 1) { lat_rad -= 0.0001; delay(10); } if (GO.BtnA.wasPressed() == 1) { zoom++; } if (GO.BtnB.wasPressed() == 1) { zoom--; } if (GO.BtnSelect.isPressed() == 1) { GO.lcd.setBrightness(brightness); brightness--; } if (GO.BtnStart.isPressed() == 1) { GO.lcd.setBrightness(brightness); brightness++; } if (lat_rad > 85.05112878) lat_rad = 85.05112878; if (lat_rad < -85.05112878) lat_rad = -85.05112878; if (lon_deg > 180) lon_deg = 180; if (lon_deg < -180) lon_deg = -180; if (zoom > 16) zoom = 16; if (zoom < 5) zoom = 5; if (brightness > 254) brightness = 254; if (brightness < 1) brightness = 1; //redraw only when something has changed if (old_lat_rad != lat_rad || old_lon_deg != lon_deg || old_zoom != zoom || firstRun) { double posX, posY, fractpart, intpart; //calculate from coordinates to tile numbers tileX = long2tilex(lon_deg, zoom); tileY = lat2tiley(lat_rad, zoom); //fractional part is the position of the your coordinats in the tile posX = modf(tileX , &intpart); posY = modf(tileY , &intpart); posX = (posX * TILE_SIZE) + (abs(DISPLAY_WIDTH - TILE_SIZE)); posY = (posY * TILE_SIZE); //redraw only when something has changed if (uint16_t(old_tileX) != uint16_t(tileX) || uint16_t(old_tileY) != uint16_t(tileY) || old_zoom != zoom || firstRun) { String path = "/TILES/" + String(uint16_t(zoom)) + "/" + String(uint32_t(tileX)) + "/" + String(uint32_t(tileY)) + ".jpg"; Serial.println(path); if (SD.exists(path)) { Serial.println("File found."); GO.lcd.clear(); GO.lcd.setCursor(0, 0); //drawJpgFile(fs::FS &fs, const char *path, uint16_t x = 0, uint16_t y = 0, uint16_t maxWidth = 0, uint16_t maxHeight = 0, uint16_t offX = 0, uint16_t offY = 0, jpeg_div_t scale = JPEG_DIV_NONE), GO.lcd.drawJpgFile(SD, path.c_str(), (abs(DISPLAY_WIDTH - TILE_SIZE))); } else { GO.lcd.println(""); GO.lcd.println("Debug:\nFile not found."); Serial.println("File not found."); } firstRun = false; } GO.lcd.drawRect(int32_t(posX), int32_t(posY), 4, 4, RED); GO.lcd.fillRect(0, 0, abs(DISPLAY_WIDTH - TILE_SIZE), DISPLAY_HEIGHT, BLACK); GO.lcd.setCursor(0, 0); GO.lcd.println("Battery:"); GO.lcd.println(String(GO.battery.getPercentage()) + "%"); GO.lcd.println("Lon_deg:"); GO.lcd.println(String(lon_deg, 6)); GO.lcd.println("Lat_rad:"); GO.lcd.println(String(lat_rad, 6)); GO.lcd.println("Zoom:"); GO.lcd.println(String(zoom)); Serial.println(String(tileX, 6)); Serial.println(String(tileY, 6)); Serial.println(String(posX)); Serial.println(String(posY)); Serial.println(zoom); Serial.println(String(lon_deg, 6)); Serial.println(String(lat_rad, 6)); old_tileX = tileX; old_tileY = tileY; } old_lat_rad = lat_rad; old_lon_deg = lon_deg; old_zoom = zoom; } double long2tilex(double lon, double z) { return (double)((lon + 180.0) / 360.0 * pow(2.0, z)); } double lat2tiley(double lat, double z) { return (double)((1.0 - log( tan(lat * M_PI / 180.0) + 1.0 / cos(lat * M_PI / 180.0)) / M_PI) / 2.0 * pow(2.0, z)); } double tilex2long(int x, int z) { return x / pow(2.0, z) * 360.0 - 180; } double tiley2lat(int y, int z) { double n = M_PI - 2.0 * M_PI * y / pow(2.0, z); return 180.0 / M_PI * atan(0.5 * (exp(n) - exp(-n))); }
Reference
https://forum.odroid.com/viewtopic.php?f=162&t=33629 https://youtu.be/-4kA_KhIvus https://github.com/ripper121/OdroidGoOSMGPSOffline https://youtu.be/BQWwTZANGlE
Be the first to comment