Navegation system
- 4 Devlogs
- 17 Total hours
A simple automatic Nav system in C
A simple automatic Nav system in C
The feedback from the certification reviewer included a clear suggestion for the next step: make the map dynamic, and possibly allow variable dimensions instead of keeping it fixed at 10×10. That’s what I focused on in this stage.
The first challenge was realizing that a normal C array, such as char lab[10][10], isn’t suitable for this. The size of a regular array has to be known at compile time, but in this case the dimensions are only known after the user enters them at runtime. The solution was to use dynamic memory allocation with malloc.
For a dynamic 2D map, this is done in two steps: first, allocate an array of pointers (one for each row), then allocate each row individually.
char **lab = malloc(rows * sizeof(char *));
for (int i = 0; i < rows; i++) {
lab[i] = malloc(columns * sizeof(char));
}
The eh_obstaculo function, which previously had the entire maze hardcoded inside it, became much simpler. It now just receives the map as a parameter (char **lab) and checks the requested position.
int eh_obstaculo(int x, int y, char **lab) {
return lab[x][y] == '#';
}
To populate the map, I use fgets to read each row entered by the user, rather than asking for one position at a time, which would have been much more tedious to use.
The part that took the most work wasn’t the map itself, but realizing that every other data structure used by the BFS (visited, parent, and queue) also depended on the old fixed TAM value. They all had to be converted to dynamically allocated structures based on the number of rows and columns. The parent array, for example, became an int *** because each cell stores a pair of coordinates (x, y) representing its parent, which adds another level of indirection.
In the end, the program asks the user for the number of rows and columns, reads the map line by line, runs the BFS using these dynamic structures, and finally frees all allocated memory with free, including the parent array, which has to be released from the innermost allocations outward because of its three levels of allocation.
The biggest lesson from this stage was realizing that making the map “dynamic” isn’t just about changing one variable. It means redesigning the entire chain of data structures that depended on the original fixed-size implementation.
After submitting the project for certification I ran into a problem that hadn’t even crossed my mind: the program simply didn’t run on Windows. I got feedback from a reviewer with a video of the error, and the message was clear, “clear is not recognized as an internal or external command.”
The explanation is simple once you get it. I had written and tested the code only on my Linux environment, and used system("clear") to clear the screen between each frame of the animation. Turns out clear is a command that exists on Linux and Mac, but on Windows the console uses cls. I’d never thought about this because I’d never tested outside my own system.
The fix was to use a preprocessor directive, #ifdef _WIN32, which lets the compiler choose which code to include depending on the operating system the program is being compiled on. This way the clear() function decides on its own whether to call system("cls") or system("clear"), without me having to maintain two separate versions of the file.
void clear() {
#ifdef _WIN32
system("cls");
#else
system("clear");
#endif
}
While reviewing the code I realized there was a second problem waiting to happen. I was using usleep() to control the timing between animation frames, and that function is also exclusive to Unix-like systems, it doesn’t exist on Windows. It probably wouldn’t have thrown an error right there in the video, but it would have further down the line as soon as the robot started moving. I solved it the same way, creating my own esperar_ms() function that uses Sleep() on Windows (which works in milliseconds) and usleep() on Linux (which works in microseconds), and swapped out all the old calls for this new function.
void esperar_ms(int ms) {
#ifdef _WIN32
Sleep(ms);
#else
usleep(ms * 1000);
#endif
}
The annoying part wasn’t so much writing the fix, it was realizing I had to test both versions before requesting re-certification again. I compiled it again on Linux to make sure I hadn’t broken anything, and the program still worked fine, I just got some unused variable warnings that were already there before and have no impact on execution.
The lesson I’m taking from this is that testing only on your own operating system gives a false sense that the program “is ready.” Only an external test or review catches these things, because in my own environment I would never have seen this error myself.
C Navigation System — Devlog #2
BFS Pathfinding & Automatic Navigation
So after the first version I wasn’t really satisfied. The robot moving manually was cool to build but it felt incomplete — a robot that needs a human to tell it where to go isn’t really a robot. I wanted it to find the path on its own.
The problem was I had no idea how BFS worked.
I spent a good chunk of the 7 hours on this just trying to understand the algorithm before touching any code. Watched some explanations, drew it out on paper, tried to wrap my head around queues and how you actually backtrack to reconstruct a path. It took a while. The moment it clicked was when I stopped thinking about it as “visiting nodes” and started thinking about it as water spreading through a maze — it fills every reachable cell layer by layer until it hits the destination.
Once that made sense, I rebuilt the project. The grid went from 5x5 to 10x10 with a more complex obstacle layout. I separated the map logic into its own function (eh_obstaculo) so the maze can be edited without touching anything else. The BFS itself uses a queue array, a visited matrix, and a parent matrix — the parent matrix is what lets you trace back the full path once you reach (9,9).
The animation was actually the fun part. After the path is reconstructed, the board redraws at each step with clear() and usleep(), showing the robot moving tile by tile. It even replays at the end at a faster speed. Seeing it run for the first time was genuinely satisfying.
The hardest part was getting the path reconstruction right — BFS gives you the path backwards, so you have to reverse it before animating. Took me a few tries to get that sorted.
C navigation system, a robot in a 5x5 maze
Built a C program that simulates a robot navigating a 5x5 grid with obstacles.
What’s done so far:
A dynamically drawn 5x5 board, with . (free path), # (obstacles), D (destination), and X (robot)
Obstacle layout stored in a separate map (lab, using l=free and p=wall), so the map can be edited easily without touching the rest of the logic
Movement controlled by directions (North/South/East/West), one tile at a time
Bounds checking (can’t leave the grid) and collision checking (can’t move through obstacles)
Board redraws after every move
Win message when reaching the destination at (4,4)