0

Line 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 RobotLine(); // 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, RobotLine. If we changed the line to "new RobotMaze()", the program flow would take a quite different route, starting robot for RCJ Rescue Maze. 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 RobotLine (or Robot) class.

Do not look for run() in RobotLine - 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 line 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 arena? 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 is C++ mandatory program structure. But, once we do it, it will be easier for us in the long run.

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

mrm-robot-line.h

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

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

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

	// Actions' declarations
...
	ActionLineFollow* actionLineFollow;
	ActionRCJLine* actionRCJLine;
...
Here, a pointer is declared. This a way to form "has" relationship between RobotLine and ActionRCJLine: RobotLine "has" ActionRCJLine. We will be using this pointer as an exclusive way to get to this action.

Next, actual declaration:

/** Start RCJ Line run.
*/
class ActionRCJLine : public ActionBase {
	void perform() { ((RobotLine*)_robot)->rcjLine(); }
public:
	ActionRCJLine(Robot* robot) : ActionBase(robot, "lin", "RCJ Line", 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 rcjLine(), and some base constructor's arguments: "lin" and "RCJ Line". Look at the comments before all actions in code to find explanations. The 2 strings define what will be displayed in menu and rcjLine() 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-line.h is the declaration of the rcjLine() function, the one action uses to do its task:

	/** Starts the RCJ Line run after this action selected.
	*/
	void rcjLine();

mrm-robot-line.cpp

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

	// All the actions will be defined here; the objects will be created.
...
	actionObstacleAvoid = new ActionObstacleAvoid(this);
	actionWallFollow = new ActionWallFollow(this);
It resides in RobotLine's constructor, the part that is executed right during the creation of the RobotLine object.

Finally, we have to implement rcjLine() function:

/** Starts the RCJ Line run after this action selected.
*/
void RobotLine::rcjLine() {
...
}