0

Maze Robot - actions

Program's start

Entry point is imposed by Arduino's design: function setup() in MRMS_ESP32.ino:

Robot *robot;

void setup() {
	robot = new RobotMaze(); // RobotLine, RobotSoccer, or Your custom robot
	robot->run();
}
robot is declared as a pointer to the base class, Robot. Crucial line is the one containing new operator, which defines it as a pointer to Robot's derived class, RobotMaze. If we changed the line to "new RobotLine()", the program flow would take a quite different route, starting robot for RCJ Rescue Line. The next line starts the robot. Note that this function has to be implemented in RobotLine as well as in RobotMaze. What it will do, it depends on the line before. At this point we can say goodbye to .ino because the program will never return here. Let's see where it landed in RobotMaze (or Robot) class.

Do not look for run() in RobotMaze - You will not find it there. It resides in Robot.cpp (and header Robot.h). You can check how it looks like but we will not consider its details here in order not to spend too much time before getting to our maze robot's logic. In short, run() is the main loop and it manages Action objects, therefore distributing workflow. It is not normally advisable to change this function or any other in Robot class. For You it is only important to know how to start the actions You need.

ActionBase actions

So, how to start the program logic that will drive the robot through the maze? We mentioned ActionBase class before. Let's investigate how it can do some useful work for us. Unfortunately, each ActionBase's derived class has to be programmed in 6 different places. This as C++ mandatory program structure. But, once we do it, it will be easier for us in the long run.

Our action is called ActionRescueMaze. It is easy to find all the 6 places by searching code with Ctrl-F.

mrm-robot-maze.h

First, class forward declaration, near the beginning of mrm-robot-maze.h:

/* All the Action-classes have to be forward declared here (before RobotMaze) as RobotMaze declaration uses them. The other option would be
not to declare them here, but in that case Action-objects in RobotMaze will have to be declared as ActionBase class, forcing downcast later in code, if
derived functions are used.*/
...
class ActionMoveTurn;
class ActionRescueMaze;
class ActionWallsTest;
You can see this declaration one line before the last, among other ActionBase derived classes.

A little lower, in the same file, You will find the following block:

	// Actions' declarations
...
	ActionMoveTurn* actionMoveTurn;
	ActionRescueMaze* actionRescueMaze;
...
Here, a pointer is declared. This a way to form "has" relationship between RobotMaze and ActionRescueMaze: RobotMaze "has" ActionRobotMaze. We will be using this pointer as an exclusive way to get to this action.

Next, actual declaration:

/** Start RCJ Rescue Maze run.
*/
class ActionRescueMaze : public ActionBase {
	void perform() { ((RobotMaze*)_robot)->rescueMaze(); }
public:
	ActionRescueMaze(Robot* robot) : ActionBase(robot, "maz", "Rescue Maze", 1) {}
};
In this declaration we even defined perform() function and constructor so that we are not forced to split the code to even more locations. If You compare this code with other actions, You will see that they are very similar, differing only in perform(), where our code calls rescueMaze(), and some base constructor's arguments: "maz" and "Rescue Maze". Look at the comments before all actions in code to find explanations. The 2 strings define what will be displayed in menu and rescueMaze() is the actual action, function that implements this behaviour. When we define this function, our work will be done.

The last part in mrm-robot-maze.h is the declaration of the rescueMaze() function, the one action uses to do its task:

	/** Starts RCJ Rescue Maze run.
	*/
	void rescueMaze();

mrm-robot-maze.cpp

Let's move to mrm-rob-maz.cpp, where the rest of code is. Find this block:

	// All the actions will be defined here; the objects will be created.
...
	actionMoveTurn = new ActionMoveTurn(this);
	actionRescueMaze = new ActionRescueMaze(this);
It resides in RobotMaze's constructor, the part that is executed right during the creation of the RobotMaze object.

Finally, we have to implement rescueMaze() function:

/** Starts RCJ Rescue Maze run.
*/
void RobotMaze::rescueMaze() {
...
}