Line Robot - Program flow
Overview
Programming is skill that is difficult to master. Learning programming language's syntax is easy part. You can program many simple tasks, getting some confidence. However, doing more complicated tasks may be harder. Much harder. That is the reason why majority of software projects end either exceeding time limit, budget, or lacking features, quite often failing in 2 or even 3 of these objectives. That is also reason why some programmers are 20 times more productive than the others. You can be a world-class expert in coding, but if You take a wrong approach, no coding skill will get You out of wood.
Can robot project be complicated? You bet they can. Robocup project can be, too. So, our advice is: do not take wrong paths and here comes one that many unwary RCJ programmers took: linear program, consisting of mega-functions and long switch statements. While easy in the beginning, debugging and further development gets harder and harder as code base increases. Do not go that way! Continue using ML-R code structure and You will be a better programmer. How to do that? Unless You are experienced, You will have to learn some concepts in this lesson and the ones that follow. Spend some time to study the content.
State machine
Processes in our environment are not linear but either pause in some states or have a group of similar features. That is the reason we can distinguish different "
states" of the process. In RCJ line the states can be "robot follows line", "robot catches a ball", etc. Your first task is to identify the states. For RCJ line, expected number can be between 10 and 30, but the numbers are not strict. Theory calls our concept "
state machine".
Our robot can change its states. There is a way to picture that in a graph, a state machine diagram, and here we can see a very simple one. All the states are in rectangles and arrows show how the states can change. How can we make a bad program that implements this graph? It is easy. Being lazy to accept new knowledge, and already knowing function loop(), why reinvent the wheel? We decide that loop() will be our program, and write it in this way:
...
void RobotLine::loop(){
int state = LINE;
...
if (state == LINE){
...
// a long code
...
}
else if (state == OBSTACLE){
}
...
// a long code
...
}
else if (stat == EVACUATION_AREA){
}
...
// a long code
...
} else ...
...
}
This will be a mess. Changing "if" statements with "switch" and invoking functions will not correct all the problems.
Actions
So, how to make a good program then? Start with learning term "action", which is an object that encapsulates a state and all the functions that are specific to that state. For example, for state "robot follows line" we may define action "ActionLineFollow". The most prominent function in this state is guiding the robot to follow line. Therefore, this action should have function "lineFollow()". And indeed, out mrm-robot-line.cpp code contains both ActionLineFollow and lineFollow(). There are other appropriate actions and functions: ActionObstacleAvoid with function obstacleAvoid(), ActionEvacuationZone with function evacuationZone(), etc.
Having separate actions is of no use if the robot cannot change its state (its current action). But it can. An example:
void RobotLine::lineFollow() {
...
if (obstacleFound())
actionSet(actionObstacleAvoid);
else if (longTimeNoLine())
end();
}
...
void RobotLine::obstacleAvoid() {
...
if (lineFound())
actionSet(actionLineFollow);
}
Explanations:
- "actionSet()" changes robot's current action (state) into u new one.
- "end()" changes robot's action into "do nothing, just display menu". The result is menu You see and You can enter a new command.
- Functions obstacleFound(), longTimeNoLine(), and lineFound() do not exist. They just have suggestive names so you can deduce what they should be doing. Therefore, do not try to run this code.
The program changes states between line following and obstacle avoiding until it detected no line for a long time, while line following, and then it exits the program, displaying the usual menu.
One thing is missing: how to start the program. We are lucky that each action can (but needn't) be listed in menu, so it can be invoked from there. ActionLineFollow is one of the actions that is listed and can be started by typing "lin". You can have different actions, each having its menu entry, and You can choose any. Can You do the same with the bad example earlier? You can't.
Generic actions
You can, and should, define Your own actions. Unfortunately, C++ imposes some restrictions that will force You to add some short code in a few places. To make it easier for You, 10 actions are predefined: ActionLoop0(function loop0()), ActionLoop1, ..., ActionLoop9. All can be started from menu. Type "gen" to enter a submenu where they are located. You can change the names to suit Your needs. For example ActionLoop0/loop0() can be changed into ActionSlope/slope().
The generic actions can serve a different purpose: You can have 10 different test functions that You can use without re-uploading program.
If You search mrm-robot-line.h and mrm-robot-line.cpp for strings "ActionLoop0" and "loop0(", You will easily find where they are located. If You wish to add new actions, just append Your definitions after these locations.