Micromouse Applied OOP Technique - A new approach, Various derived Micromouse, Class map for the OOP applied Micromouse Robot, Brain and Body Management Class, Maze Representation Class, Simulation Class
Micromouse Applied OOP Technique - A new approach, Various derived Micromouse, Class map for the OOP applied Micromouse Robot, Brain and Body Management Class, Maze Representation Class, Simulation Class
A new approach Micromouse and OOP
Based on object-oriented theory, I redefined and systematized the Micro Mouse robot. Classes were defined, and inheritance was used to inherit characteristics from the systematized superclass. From children to elders, the robot could be modified to suit their needs, mimicking the natural behavior of an animal.
This Micromouse used the encapsulation, inheritance, polymorphism, abstraction which is a programming methodology that organizes code into objects and classes. These principles are extremely useful in robotics applications like Micromouse. I would like to share my experience of writing based on actual application.
In this process, I applied the flood fill technique to capture the cerebrum instinct for direction selection, and for the cerebellum's movement, I controlled the motors with UV sensors and PIDs to mimic mouse movement. The flood fill logic was derived from the GitHub adam2392’s source code, and the motor control logic was derived from the GitHub ukmars’s source code, both modified to fit the intended purpose.
I had to check my maze search algorithm, and I was able to do so using the maze simulation on GitHub mms and maze files. I would like to thank to Adam Li of adam2392, Peter Harrison of ukmars and Mack of mms for their contributions. I implemented the software using the STM32F411CEU6 Black Pill.
Various Micromouse derived from a single class
Baby Mouse
Young mouse
A young mouse has developed somewhat physically, its memory has improved, and it can even run. It repeatedly stops and goes one block at a time, checking for surrounding walls. At forks, it prefers to go straight ahead, but if it’s already been there, it uses its instinct (flood fill) to choose a different direction. If a block is blocked on all sides, it turns around and, without sensing, it quickly runs to the remembered fork. At this time, if the maze path is in the shape of a zig zag, it turns 45 degrees diagonally and runs in a straight line. It uses the same method to find the goal point and return to the starting point.
Young adult mouse
A young adult mouse is physically developed more, has significantly improved memory, and can run for long distances. Move half a block ahead and check whether there is a wall in the block in front of it before deciding on its movement. It moves quickly, one block at a time, without stopping, checking for surrounding walls. At a forks, it takes the straight path first. However, if it’s already been to a block, it compares the number of times it’s passed it in each direction, choosing the shorter path and continuing the movement. If a block is blocked on all sides, it turns around, and without sensing, it quickly run to the remembered fork and change direction by making a curved turn. At this time, if the maze path is in the shape of a zig zag, it turns 45 degrees diagonally and runs in a straight line. Do this until it finds the goal point but when it returns to the starting point, uses its instinct(flood fill) to determine the direction at the fork in the maze.
Adult mouse
An adult mouse is physically mature. It moves in the same way as a young adult mouse such as making curved turns, 45 degree turns, etc., but it uses instinct (flood fill) to determine direction at forks in the maze. It uses the same method to find the goal point and return to the starting point.
Old mouse
An old mouse, though physically old, possesses a wealth of experience. It moves in the same way as an adult mouse, but thanks to Lidar, it can see the front wall of the block far ahead, moving quickly in the forward direction and navigating at forks by instinct (flood fill). It uses the same method to find the goal point and return to the starting point.
Reference : YouTube Video
Class map for the OOP applied Micromouse Robot
A Micromouse software system can be divided into several classes.
Main Classes
Encapsulation in Micromouse
Encapsulation means hiding internal data and exposing only necessary functions.
For example, the motor speed should not be modified directly from everywhere in the code.
Example Concept
class Motor {
private:
int speed;
public:
void setSpeed(int s) {
speed = s;
}
int getSpeed() {
return speed;
}
};
In this example:
-
The variable
speedis private - Only specific methods can access it
- This prevents accidental modification
Encapsulation improves system safety and stability.
Abstraction in Micromouse
Abstraction hides complex implementation details and provides simple interfaces.
For example, reading a sensor may involve:
- ADC conversion
- Filtering
- Calibration
- Noise reduction
But the main program only needs:
sensor.readDistance();
The internal complexity is hidden from the user.
Advantages
- Simplifies programming
- Reduces code complexity
- Makes the robot easier to maintain
Inheritance in Micromouse
Inheritance allows one class to reuse features from another class.
This is useful when different sensors or motors share common behavior.
Example
class Sensor {
public:
virtual int read() = 0;
};
class IRSensor : public Sensor {
public:
int read() override {
return analogRead(A0);
}
};
Here:
-
IRSensorinherits fromSensor - Common functionality is reused
- Code duplication is reduced
Inheritance makes large robotic systems easier to expand.
Polymorphism in Micromouse
Polymorphism allows the same function name to behave differently depending on the object type.
This is useful for supporting multiple sensor types.
Example
Sensor* sensor;
sensor = new IRSensor();
sensor->read();
sensor = new UltrasonicSensor();
sensor->read();
The same read() function works differently depending on the sensor object.
Benefits include:
- Flexible architecture
- Easier upgrades
- Cleaner code
OOP-Based Micromouse Architecture
A well-designed Micromouse project usually follows layered architecture.
Hardware Layer
Handles:
- Sensors
- Motors
- Encoders
- Battery monitoring
Control Layer
Handles:
- PID control
- Speed regulation
- Turning algorithms
Navigation Layer
Handles:
- Flood-fill algorithm
- Maze exploration
- Shortest path calculation
Application Layer
Handles:
- Robot modes
- Start sequence
- User interaction
OOP makes it possible to separate these layers efficiently.
Body Management Class
Body control is the most important part of a Micromouse robot for a movement like a physical body.
Major Features
- This class must have the corresponding class, just as a body has arms, legs, chest, eyes, and a mouth
- Manage each physical parts of a body
Define the class for Body
class CBody {
public:
CBody();
virtual ~CBody();
// Objects
CDriveProfile objMindForward, objMindRotation;
CDriveSensors objEyes;
CDriveEncoders objArms;
CDriveMotors objLegs;
CDriveReports objMouth;
bool controllers_output_enabled;
float old_fwd_error;
float old_rot_error;
float fwd_error;
float rot_error;
float steering_adjustment;
void enable_motor_controllers();
void disable_motor_controllers();
float position_controller();
float angle_controller();
void start_motor_controllers();
void reset_motor_controllers();
void update_motor_controllers();
void BodyInits();
void BodyResets();
void BodyUpdates();
void BodyDisplay();
};
Motor Control Class
Motor control is one of the most important parts of a Micromouse robot for a movement. Used N20 micro metal gearmotor MP 6V with extended motor shaft.
Major Features
- Driving by volts
- PWM generation
- Direction control
- Braking system
Define the class
class CDriveMotors {
public:
CDriveMotors();
virtual ~CDriveMotors();
typedef enum
{
DIRECTION_CCW = 0, ///< Counter-Clockwise
DIRECTION_CW = 1 ///< Clockwise
} Direction;
float battery_scale;
float left_motor_volts, right_motor_volts;
void init(void);
void reset_motors(void);
void update_motors(float left_volts, float right_volts);
void stop_motors(void);
void setPWMLeft( uint16_t LpwmA, uint16_t LpwmB);
void setPWMRight(uint16_t LpwmA, uint16_t LpwmB);
void set_left_motor_pwm( int pwm);
void set_right_motor_pwm(int pwm);
void set_left_motor_volts( float volts);
void set_right_motor_volts(float volts);
};
This design makes motor management simple and reusable. Since this class acts like a leg, the corresponding object is represented as objLegs like CDriveMotors objLegs in CBody class.
IR Sensor Management Class
IR Sensor control is one of the most important parts of a Micromouse robot for a movement.
Major Features
- Detects the distance and presence of walls
- Read a analog value from the sensors through ADC
- Calculate for a steering and manage
Define the class for IR sensor
class CDriveSensors {
public:
CDriveSensors();
virtual ~CDriveSensors();
/*** wall sensor variables ***/
int front_wall_sensor;
int left_wall_sensor;
int right_wall_sensor;
int front_wall_sensor_raw;
int left_wall_sensor_raw;
int right_wall_sensor_raw;
/*** true if a wall is present ***/
bool left_wall_present;
bool front_wall_present;
bool right_wall_present;
/*** steering variables ***/
bool steering_enabled;
/*** Local variables ***/
float last_steering_error = 0;
float steering_adjustment;
uint16_t battery_adc_reading;
uint8_t cc1Flag = 0;
// Functions
void init();
void reset_sensors();
void update_sensors(float *battery_scale, float *steering_adjustment) ;
float update_battery_voltage();
float update_wall_sensors();
void reset_steering();
void enable_steering();
void disable_steering();
float calculate_steering_adjustment(float error);
short SensorsDisplay(void);
uint16_t GetValue(int which) ; // read value
uint16_t MotorPower(void);
uint16_t ADC_Select_CHx( uint32_t Channel );
void IR_pulse(GPIO_TypeDef *GPIOPort, uint16_t GPIOPin) ;
//
inline int get_left_sensor() ;
inline int get_front_sensor() ;
inline int get_right_sensor() ;
inline void wait_for_front_sensor() ;
};
This design makes IR sensor management simple and reusable. Since this class acts like a eye, the corresponding object is represented as objEyes like CDriveSensors objEyes in CBody class.
Encoder Management Class
Encoder control is one of the most important parts of a Micromouse robot for a movement. Used quadrature encoders to micro metal gearmotors extended back shaft that uses a magnetic disc and Hall effect sensors to provide 12 counts per revolution of the motor shaft.
Major Features
- Read a value from encoders through STM32 Encoder timer
- Detects the distance and angle for the movement
- Calculate for a steering and manage
Define the class for Encoder sensor
class CDriveEncoders {
public:
CDriveEncoders();
virtual ~CDriveEncoders();
float s_robot_position;
float s_robot_angle;
float s_robot_fwd_increment ;
float s_robot_rot_increment ;
int32_t prevLEnc;
int32_t prevREnc;
int32_t left_total;
int32_t right_total;
// Functions
void init(void);
void reset_encoders();
void update_encoders();
float robot_fwd_increment();
float robot_rot_increment();
float robot_position();
float robot_angle();
int32_t LEnc(void);
int32_t REnc(void);
};
Profile Management Class
Profile control is one of the most important parts of a Micromouse robot for a movement.
Major Features
- Read a value from sensor and encode class
- Detects the velocity and acceleration for the movement by PID
- Calculate for a steering and manage
Define the class for Encoder sensor
class CDriveProfile {
public:
CDriveProfile();
virtual ~CDriveProfile();
void init();
void reset();
void update();
void clear_counters();
bool is_finished();
void start(float distance, float top_speed, float final_speed, float acceleration);
void stop();
void set_state(ProfileState state) ;
float get_braking_distance();
float position();
float speed() ;
float increment();
float acceleration();
void set_speed(float speed);
void set_target_speed(float speed);
void adjust_position(float adjustment);
void set_position(float position);
void finish() ;
private:
volatile uint8_t m_state = CS_IDLE;
volatile float m_speed = 0;
volatile float m_position = 0;
int8_t m_sign = 1;
float m_acceleration = 0;
float m_one_over_acc = 1;
float m_target_speed = 0;
float m_final_speed = 0;
float m_final_position = 0;
};
Brain Management Class
Brain control is the most important part of a Micromouse robot for a movement.
Major Features
- It consists of the cerebrum, which governs judgment in the maze, and the cerebellum, which governs behavior
- Manage how to operate the mouse robot in the maze
- Presents the basic behaviors of all mouse robots
Define the class for Brain
class CBrain : public Cerebrum, public Cerebellum {
public:
CBrain();
virtual ~CBrain();
uint8_t mouse_direction= NORTH;
uint8_t mouse_x = 0, mouse_y = 0;
uint8_t goal_x = 0, goal_y = 0;
void BrainInit( Simulation *smp, CBody *objBody );
bool FindGoal ( bool mode );
bool StartToGoal(uint8_t startDir);
bool GoalToStart(uint8_t startDir);
uint8_t HowToGo ( uint8_t * mx, uint8_t * my, uint8_t * mdir, bool direction ); // thiking
uint8_t MoveAction(Queue * this_queue, uint8_t startDir); // moving
bool CheckBoundary( );
};
Cerebellum Management Class
Cerebellum control is one of the most important parts of a Micromouse robot for a small brain.
Major Features
- Mainly manages movements
- Go straight, rotate, stop, 45 or 90 degree turn
- Also manage a smooth curve turn
Define the class for Cerebellum
class Cerebellum {
public:
Cerebellum();
virtual ~Cerebellum();
CBody *pBody;
Simulation *hsmp;
Buffers bufs;
Queue *mouse_queue, *visit_queue;
short mouse_pose = 0;
bool leftWall;
bool frontWall;
bool rightWall;
void CerebellumInit(Simulation *smp, CBody *objBody );
void TestMoving(Simulation *simp);
void stopAndAdjust();
void end_run();
void stop_at(float distance);
void stop_after(float distance);
void wait_until_position(float position);
void wait_until_distance(float distance);
void turn(float angle, float omega, float alpha);
void spin_turn(float degrees, float speed, float acceleration);
void turnLeft45(void);
void turnRight45(void);
void turnLeft90(void);
void turnRight90(void) ;
void turnBack(void);
void moveEdgeForward(short length);
void moveHalfForward(short length);
void moveFullForward(short length);
void smoothLeft90(void);
void smoothRight90(void);
void smoothTurnBack(void);
void smoothFullForward(short length);
void turnSub(int mode);
void moveSub(int mode, short length);
void smoothSub(int mode);
void readyToGo(void);
};
Cerebrum Management Class
Cerebrum control is one of the most important parts of a Micromouse robot for a big brain.
Cerebrum control is one of the most important parts of a Micromouse robot for a big brain.
Major Features
- The mouse robot mainly decides where to go in the maze
- Use Flood-fill algorithm for a thinking
- Find the optimized path from the visited cells
- The mouse robot mainly decides where to go in the maze
- Use Flood-fill algorithm for a thinking
- Find the optimized path from the visited cells
Define the class for Cerebrum
class Cerebrum {
public:
Cerebrum();
virtual ~Cerebrum();
Buffers Bufs;
Nodes ns;
Floodfill fdf;
Simulation *hSmp;
const char *dir_ch[16] = { "N","E","S","W","NE","NW","SE","SW","EN","ES","WN","WS","err12","err13","err14","OT" };
struct {
uint8_t left;
uint8_t forward;
uint8_t right;
} WallInfo[4] = { {WEST, NORTH,EAST}, {NORTH, EAST, SOUTH }, {EAST, SOUTH, WEST}, {SOUTH,WEST,NORTH} } ;
MazeCells *mouse_maze; // maze for keeping track of flood values and walls
Stack *mouse_stack; // stack used for flood fill
bool flooded = false;
void CerebrumInit(Simulation *simp);
void SetResources (void);
void ResetResources(void);
MazeCells * new_Maze (void);
void delete_Maze (void);
void print_map (void);
// update flag for whether goal or start cell was reached
bool check_start_reached ( Node *this_node, bool * found_start) ;
bool check_goal_reached ( Node *this_node, bool * found_goal) ;
// save or read the shortest path
bool ReadPath ( Queue *this_queue );
bool WritePath( Queue *this_queue );
// function for updating the location and direction of mouse
void OptimizePath(void) ;
void StartToGoalReflooding( uint8_t x , uint8_t y );
void GoalToStartReflooding( uint8_t x , uint8_t y );
void SetGoalWall( Node *this_node, uint8_t mdir);
void SetWall ( Node *this_node, const uint8_t dir);
void SetWallCell( Node *this_node, uint8_t mdir, bool wallFront, bool wallLeft, bool wallRight );
void Reflooding ( Node *this_node, bool direction);
void PathDisplay(uint8_t dir, uint8_t dis, uint8_t mx, uint8_t my, bool pass);
int Diff_Angle(uint8_t sr, uint8_t ds);
uint8_t EdgeRunDirection(uint8_t dir, uint8_t next_dir);
uint8_t GetNextDirection ( Node *this_node, uint8_t mdir, bool direction );
uint8_t GetNextDirectionSub( Node *this_node, uint8_t mdir, bool direction );
};
Maze Representation Class
The maze must be stored digitally inside memory.
Maze Class Responsibilities
- Store wall information
- Mark visited cells
- Save distance values
- Update maze map
Define the class for Maze
- Define the node type and class as the basic unit for storing maze cell information
- Declare it to correspond to the maze size
- Execute to initialize the state of each cell in Cerebrum class
- As the robot moves forward, it stores the direction of travel and information about the left and right walls in that direction based on information obtained by sensors
typedef struct Node { /* data fields */
bool visited;
short floodval;
uint8_t x;
uint8_t y;
uint8_t exitedDir : 4;
uint8_t enteredDir : 4;
uint8_t pathCount : 2;
uint8_t passCount[4]; // each direction's pass count
struct Node * neighbours[4]; // pointers to neighbors
} Node;
class Nodes {
public:
Nodes();
virtual ~Nodes();
int debug_on = false; /* debug flag */
// Node Functions
Node * new_Node (const uint8_t x, const uint8_t y); // (x, y)
void delete_Node (Node ** npp);
};
typedef struct MazeCells {
Node * Block[SIZE][SIZE]; // x, y
} MazeCells;
/* MazeCells Constructor */
MazeCells * Cerebrum::new_Maze (void) {
MazeCells * mouse_maze;
uint8_t i, j;
mouse_maze = (MazeCells *) malloc(sizeof(MazeCells));
/* Allocate a new Node for each coord of maze */
for (i = 0; i < SIZE; ++i)
for (j = 0; j < SIZE; ++j)
mouse_maze->Block[i][j] = ns.new_Node (i, j);
/* setting the neighbors ptrs... must be done after all cells allocated */
for (i = 0; i < SIZE; i++) {
for (j = 0; j < SIZE; j++) {
mouse_maze->Block[i][j]->neighbours[WEST] = (i == 0) ? NULL : (mouse_maze->Block[i-1][j]);
mouse_maze->Block[i][j]->neighbours[EAST] = (i == SIZE-1) ? NULL : (mouse_maze->Block[i+1][j]);
mouse_maze->Block[i][j]->neighbours[SOUTH] = (j == 0) ? NULL : (mouse_maze->Block[i][j-1]);
mouse_maze->Block[i][j]->neighbours[NORTH] = (j == SIZE-1) ? NULL : (mouse_maze->Block[i][j+1]);
}
}
return mouse_maze;
}
This keeps maze management independent from movement control.
Flood-fill Class
The maze solver controls path planning algorithms.
Major Features
- Calculate flood-fill value of each cell
- Get a flood-fill value of current cell
- Manages a stack memory of flood-fill calculation
- Update maze map
Define the class for Flood-fill
class Floodfill {
public:
Floodfill();
virtual ~Floodfill();
int debug_on = false; /* debug flag */
Buffers bufs;
void flood_fill (Node * this_node, Stack * this_stack, const short reflood_flag) ;
short floodval_check(Node * this_node) ;
void update_floodval (Node * this_node);
short get_smallest_neighbor (Node * this_node);
void push_open_neighbors (Node * this_node, Stack * this_stack);
short get_smallest_neighbor_dir (Node * this_node, const short preferred_dir);
};
Keeping algorithms in separate classes improves testing and development.
Simulation Class
This class is an interface for UART communicating with the previously mentioned simulator, mms.
Major Features
- Interface functions for simulator communication are defined
- Defined to determine the presence or absence of walls on the simulator
- Defined to specify mouse movements(straight, diagonal, rotation) on the simulator
- Defined functions for the maze map on the simulator
- Update maze map
Define the class for Simulation
class Simulation {
public:
Simulation();
virtual ~Simulation();
// API
void log(char *message);
int mazeWidth();
int mazeHeight() ;
bool FrontWallFront(int halfStepsAway) ;
bool FrontWallRight(int halfStepsAway) ;
bool FrontWallLeft(int halfStepsAway) ;
bool BackWallBack(int halfStepsAway) ;
bool BackWallRight(int halfStepsAway) ;
bool BackWallLeft(int halfStepsAway) ;
bool wallFront();
bool wallRight();
bool wallLeft() ;
bool moveFullForward(short distance);
bool moveHalfForward(short numHalfSteps);
bool moveEdgeForward(short numHalfSteps);
void runRight();
void runLeft();
void turnRight90();
void turnLeft90();
void turnRight45();
void turnLeft45();
void turnBack();
void completeRun();
void setWall(int x, int y, char direction);
void clearWall(int x, int y, char direction);
void setColor(int x, int y, char color);
void clearColor(int x, int y);
void clearAllColor() ;
void setText(int x, int y, char * text);
void clearText(int x, int y);
void clearAllText();
bool wasReset();
void ackReset();
// ----- Helpers -----
char *readline() ;
char *communicate(char * command);
bool getAck(char * command);
bool getBoolean(char * command);
int getInteger(char * command);
};
Benefits of OOP in Micromouse Development
| Benefit | Practical Impact |
|---|---|
| Modularity | Sensor code, motor code, and algorithm code can be tested independently |
| Reusability | A well-written PIDController class works for both speed and heading control |
| Maintainability | Adding a new sensor type doesn't require touching the algorithm layer |
| Testability | Mock objects can substitute for real hardware during unit testing |
| Scalability | Moving from a 4-direction to an 8-direction (diagonal) mouse is an extension, not a rewrite |
Conclusion
Object-Oriented Programming is one of the most effective techniques for developing advanced Micromouse robots. By organizing code into modular classes, developers can create cleaner, safer, and more scalable robotic systems.
OOP principles such as encapsulation, inheritance, polymorphism, and abstraction help simplify complex robot behavior while improving maintainability and debugging efficiency.
Micromouse development is far more than wiring up motors and sensors. The software architecture that ties everything together must be robust, testable, and flexible enough to evolve as the robot improves across competition seasons.
Whether you are a student building your first micromouse or an experienced competitor shaving milliseconds off your best run, applying OOP principles to your firmware will make your codebase cleaner, your debugging faster, and your competition preparation more effective.
The maze is the challenge. Good software architecture is the competitive edge.

Comments
Post a Comment