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


I would like to introduce how I utilized OOP through my own case study of actually applying it to Micromouse.


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.

MicromouseClassDiagram

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

A baby mouse is not yet physically developed and can only walk. So it repeatedly stops and starts one block at a time, checking for surrounding walls, and uses its instincts (flood fill) to determine direction at forks. If a block is blocked on all sides, it turns around and stops, continues to go and stops one block at a time without sensing until it reaches a fork in the maze. It moves in the same way when finding the goal and returning to the starting point. 

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

Mouse.h
main.cpp
(Main control system)
BodyConfig,h
CBody
CDriveEncodersTracks wheel rotation
CDriveMotorsControls wheel motors
CDriveProfileMaintains stable movemen
CDriveReportsShows debugging information
CDriveSensorsReads wall sensors
OneButtonManage two buttons
BrainConfig.h
CBrain
CerebellumSmall brain for behavior
CerebrumBig brain for thinking
BuffersTwo kind memories(Queue, Stack)
NodesStores maze data
FloodfillFloodfill algorithm
SimulationSimulation interface for the mms
H/W device control module
EEPROMStore the shottest path
SSD1306Display module
VL53L0XLidar module
CMice
Class received from the superclass(CBody, CBrain)
BabyMouselow speed, sensing right angle
YoungMouseDiagonal wall detection
YoungAdultMouseStraight-forward tendency
AdultMouseSmooth curve turning
OldMouseUsing Lidar for a front wall




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 speed is 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:

  • IRSensor inherits from Sensor
  • 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);


};


This design makes IR sensor management simple and reusable.  Since this class acts like an arm, the corresponding object is represented as objArms like CDriveEncoders objArms in CBody class.


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;

};


This design makes a profile management simple and reusable.  Since this class acts like an mind, the corresponding object is represented as objMindxxxx like CDriveProfile objMindForward, objMindRotation in CBody class. This object needs two kins for a straight and turn movements.


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.

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

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

BenefitPractical Impact
ModularitySensor code, motor code, and algorithm code can be tested independently
ReusabilityA well-written PIDController class works for both speed and heading control
MaintainabilityAdding a new sensor type doesn't require touching the algorithm layer
TestabilityMock objects can substitute for real hardware during unit testing
ScalabilityMoving 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

Popular posts from this blog

How to Build a Micromouse Robot - Mechanical, Hardware, Software

Micromouse Competitions - Types, Overview, Comparison, Advantages, Worldwide

Complete Guide to Micromouse Maze - Dimensions, Structure and Components, Building