XRAD
Well-known member
I can get a great scrolling 500x500 tft display using onboard memory. I can save data to SD, but I can;t figure out how to read SD data and implement it onto new screen frameBuffer(why: I want to have a larger storage for an x,y LIDAR occupancy map)....I did try quite a few ways before asking for help...any help appreciated!! THX!
Code:
#include "ILI9341_t3n.h"
#include <SPI.h>
#include <FastLED.h>
#include <SD.h>
#define TFT_DC 9
#define TFT_CS 10
#define TFT_RST 8
#define TFT_SCK 13
#define TFT_MISO 12
#define TFT_MOSI 11
#define SD_CS BUILTIN_SDCARD
ILI9341_t3n tft1 = ILI9341_t3n(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCK, TFT_MISO);
// Grid configuration
const int MAP_SIZE = 500;
byte grid[MAP_SIZE][MAP_SIZE]; // 0=Empty, 1=Visited, 2=Occupied
const char* dataFile = "gridlog.txt";
File myFile;
// Robot Pose
float robotX = MAP_SIZE / 2;
float robotY = MAP_SIZE / 2;
float robotHeading = 0; // Degrees
void setup() {
tft1.begin();
tft1.setRotation(0); //
//tft1.fillScreen(ST7735_BLACK);
tft1.useFrameBuffer(true); // Smooth rendering with DMA-like buffering
// Initialize SD Card
if (!SD.begin(SD_CS)) {
Serial.println("SD Card initialization failed!");
return;
}
Serial.println("SD Card initialized.");
memset(grid, 0, sizeof(grid));
}
// Generate test lidar scan
void updateLidarScan() {
for (int angle = 0; angle < 360; angle += 100) {
float rad = (angle + robotHeading) * PI / 180.0;
float dist = 50; //random(20, 50); // Random "wall" distance
// Calculate occupied point (wall)
int ox = (int)(robotX + cos(rad) * dist);
int oy = (int)(robotY + sin(rad) * dist);
if (ox >= 0 && ox < MAP_SIZE && oy >= 0 && oy < MAP_SIZE) {
// Store to SD Card
myFile = SD.open(dataFile, FILE_WRITE);
if (myFile) {
myFile.print(ox);
myFile.print(",");
myFile.println(oy);
myFile.close(); // Close to save data
myFile.print("Writing: ");
myFile.print(ox);
myFile.print(",");
myFile.println(oy);
Serial.print("ox:");
Serial.println(ox);
Serial.print("oy:");
Serial.println(oy);
} else {
Serial.println("Error opening file!");
}
grid[ox][oy] = 2; // Mark Occupied (Red)
}
}
}
void renderMap() {
// Center screen on robot pose
int camX = robotX - (tft1.width() / 2);
int camY = robotY - (tft1.height() / 2);
for (int x = 0; x < tft1.width(); x++) {
for (int y = 0; y < tft1.height(); y++) {
int gx = camX + x;
int gy = camY + y;
if (gx >= 0 && gx < MAP_SIZE && gy >= 0 && gy < MAP_SIZE) {
if (grid[gx][gy] == 2) tft1.drawPixel(x, y, ILI9341_RED);
else tft1.drawPixel(x, y, ILI9341_BLACK);
}
}
}
// Draw robot as a small yellow dot in the center
tft1.fillCircle(tft1.width() / 2 - 2, tft1.height() / 2 - 2, 8, ILI9341_YELLOW);
tft1.updateScreen(); // Push frame buffer to display
}
void loop() {
EVERY_N_MILLISECONDS(200) {
// Move robot randomly for test
robotX += random(-3, 4);
robotY += random(-3, 4);
robotHeading += random(-5, 6);
//Add new lidar data to the grid
updateLidarScan();
//draw scrolling viewport
renderMap();
}
}
Last edited: