Subject:
|
Re: Are there GOTO statements in NQC?
|
Newsgroups:
|
lugnet.robotics
|
Date:
|
Sat, 22 Nov 2003 02:54:26 GMT
|
Viewed:
|
1190 times
|
| |
| |
Thanks to you all, who have commented my imaginations.
The most veto comes from alex:
> > The creator of pascal, Nicolaus Wirth, stated: a goto is only neccesary to
> > exit a program (from its subroutines in the middle) to perform a fatal abort.
> By your own admission that it is provably possible to convert any program
> using goto into one that isn't, Niklaus Wirth's statement is provably false.
The statement does not contain the logical error you see. Ok, ok, i should have
written "subroutine" (or method) instead of program. So your are right.
> And again, this doesn't actually improve readability in several important
> cases (including state machines and finite set automata, which are well
> nigh unreadable whether you use goto or not).
Ok, this is a very important veto. A state machine is the *origin* of a
spaghetti program.
State machines are good control programs for robots, so regarding this technique
is important.
I have build, two years ago, when i bought my mindstorm set, a robot, programmed
in nqc, using a state machine to control him.
The robot had two chains, each controlled by a motor to drive forward etc.
Furthermore he had a turret whith a rotation sensor, a motor to move it and a
standard lego light sensor to measure the light intensity. The light sensor is
swept around in horizontal plane, but he cannot turn freely around because of
the light sensor cable, so he has a start, center and maximum position. The
robot has a bumper at his frontside. If the bumper switches, the robot has
reached his destination.
I have given an nqc code example at the end of this posting. Whoever loads this
program into an appropritate robot machine must know, that this code only works
ok, if the light source is on the right side of the robot, directly shining to
the light sensor. Only half of the neccesary automata is implemented! Sorry, but
i have no time, to fullfill this.
The robots program is started, when the robot is put in place, such that the
light sensor is actually illuminated. You use a spotlight as a light source.
The robot will determine the direction of the light source and turn the robot
sitting on his place, such that the light sensor is heading in a 0 degree
forward angle. Then it will drive forward until the tracor beam is broken. If
the beam is broken, the turret will scan again for maximum light, turn the robot
into that direction and move forward agian.
Now look at the way i have implemented the state machine in the "task main".
Isnt it readable? It uses subroutines to do tasks.
At first the robot has to center his rotor (light sensor). See how the states
are switching foreward. Regard it as a concept to program any state machine. As
you can imagine, a state machine does not need spaghetti goto code to fullfill
the automata program. Use the last state, to determine the next one in a C
switch statement, according to input conditions.
Greetings
Ralph
the lighteye listing:
/* leyetst22.nqc / cr: 23.Aug.2001 / lm: 21.Dez.2001 / rt */
#define ROT_EXEC_TIME 20 // *10 = ms
#define LIGHT SENSOR_1
#define ROTATION SENSOR_2
#define OBSTACLE SENSOR_3
#define SENSOR_ROTATION_MOTOR OUT_B
#define PORT_MOTOR OUT_A
#define STARBOARD_MOTOR OUT_C
int rotStart, rotEnd, rotMid;
int maxLight, maxLightRot;
task main() {
start goal_reached;
int tractorResult;
int state = 0;
int cond = 1;
while( cond ) {
switch( state ) {
case 0 : center_rotor();
state = 1;
break;
case 1 : scan_environment( rotMid-47, rotMid+47, 1 );
state = 2;
break;
case 2 : drive_rotor_max_light();
if( LIGHT < maxLight-1 ) {
state = 1;
} else {
state = 7;
}
break;
case 3 : scan_environment( rotMid-31, rotMid+31, 1 );
state = 4;
break;
case 4 : drive_rotor_max_light();
if( LIGHT < maxLight-1 ) {
state = 1;
} else {
state = 7;
}
break;
case 7 : if( ROTATION > rotMid ) {
Rev( STARBOARD_MOTOR );
Fwd( PORT_MOTOR );
On( PORT_MOTOR + STARBOARD_MOTOR );
} else if( ROTATION < rotMid ) {
Fwd( STARBOARD_MOTOR );
Rev( PORT_MOTOR );
On( PORT_MOTOR + STARBOARD_MOTOR );
}
if( ROTATION != rotMid ) {
tractor_beam( tractorResult );
}
Off( PORT_MOTOR + STARBOARD_MOTOR );
if( LIGHT < maxLight-1 ) {
state = 3;
} else {
state = 8;
}
state = 8;
break;
case 8 : Fwd( STARBOARD_MOTOR );
Fwd( PORT_MOTOR );
On( PORT_MOTOR + STARBOARD_MOTOR );
state = 8;
break;
case 9 : ClearTimer(0);
while( FastTimer(0) < 5 );
int light = LIGHT;
if( light > maxLight ) {
maxLight = light;
state = 9;
} else if( light < maxLight-1 ) {
Off( PORT_MOTOR + STARBOARD_MOTOR );
state = 3;
} else {
state = 9;
}
case 11: Off( PORT_MOTOR + STARBOARD_MOTOR );
cond = 0;
state = 9;
break;
}
}
}
task goal_reached() {
while( !OBSTACLE ) {
}
Off( PORT_MOTOR + STARBOARD_MOTOR + SENSOR_ROTATION );
StopAllTasks();
}
void init() {
SetSensor( LIGHT, SENSOR_LIGHT );
SetSensor( ROTATION, SENSOR_ROTATION );
}
void center_rotor() {
int rot;
Fwd( SENSOR_ROTATION_MOTOR );
On( SENSOR_ROTATION_MOTOR );
do {
rot = ROTATION;
ClearTimer(0);
while( FastTimer(0) < ROT_EXEC_TIME );
} while( rot != ROTATION );
Off( SENSOR_ROTATION_MOTOR );
ClearSensor( ROTATION );
rotStart = ROTATION;
Rev( SENSOR_ROTATION_MOTOR );
On( SENSOR_ROTATION_MOTOR );
do {
rot = ROTATION;
ClearTimer(0);
while( FastTimer(0) < ROT_EXEC_TIME );
} while( rot != ROTATION );
Off( SENSOR_ROTATION_MOTOR );
rotEnd = ROTATION;
rotMid = ( rotEnd - rotStart ) / 2;
do {
Fwd( SENSOR_ROTATION_MOTOR );
On( SENSOR_ROTATION_MOTOR );
while( ROTATION > rotMid );
Off( SENSOR_ROTATION_MOTOR );
if( ROTATION < rotMid ) {
Rev( SENSOR_ROTATION_MOTOR );
On( SENSOR_ROTATION_MOTOR );
while( ROTATION < rotMid );
Off( SENSOR_ROTATION_MOTOR );
}
} while( ROTATION != rotMid );
}
void scan_environment( int rotStart, int rotEnd, int useDatalog ) {
// I am in the middle, drive to rotStart
Fwd( SENSOR_ROTATION_MOTOR );
On( SENSOR_ROTATION_MOTOR );
while( ROTATION > rotStart );
Off( SENSOR_ROTATION_MOTOR );
// Drive in paused 1 steps to rotEnd
maxLight = 0;
int actRot = rotStart;
do {
PlaySound( SOUND_CLICK );
ClearTimer(0);
while( FastTimer(0) < 16 );
int light = LIGHT;
updateLightRotStatistic( light );
if( useDatalog ) {
AddToDatalog( light );
}
actRot++;
do {
Rev( SENSOR_ROTATION_MOTOR );
On( SENSOR_ROTATION_MOTOR );
while( ROTATION < actRot );
Off( SENSOR_ROTATION_MOTOR );
if( ROTATION > actRot ) {
Fwd( SENSOR_ROTATION_MOTOR );
On( SENSOR_ROTATION_MOTOR );
while( ROTATION > actRot );
Off( SENSOR_ROTATION_MOTOR );
}
} while( ROTATION != actRot );
} while( actRot <= rotEnd );
Off( SENSOR_ROTATION_MOTOR );
}
void updateLightRotStatistic( int sensorValue ) {
if( sensorValue > maxLight ) {
maxLight = sensorValue;
maxLightRot = ROTATION;
}
}
void MaxLightScan() {
ClearTimer(0);
while( FastTimer(0) < 50 );
int i;
int sumLight = 0;
for( i=0; i<10; i++ ) {
ClearTimer(0);
while( FastTimer(0) < 10 );
sumLight += LIGHT;
}
maxLight = sumLight / 10;
}
void drive_rotor_max_light() {
// I am on starboard position after scanning. Drive in port direction.
do {
Fwd( SENSOR_ROTATION_MOTOR );
On( SENSOR_ROTATION_MOTOR ); // drive to maxLightRot
while( ROTATION > maxLightRot );
Off( SENSOR_ROTATION_MOTOR );
if( ROTATION < maxLightRot ) {
Rev( SENSOR_ROTATION_MOTOR ); // Set starboard direction.
On( SENSOR_ROTATION_MOTOR ); // drive to maxLightRot
while( ROTATION < maxLightRot );
Off( SENSOR_ROTATION_MOTOR );
}
} while( ROTATION != maxLightRot );
}
void tractor_beam( int& result ) {
int dir; // o=none, 1= 2=
do {
dir = 0;
if( ROTATION > rotMid ) {
Fwd( SENSOR_ROTATION_MOTOR );
On( SENSOR_ROTATION_MOTOR ); // drive to maxLight
while( LIGHT < maxLight-1 ); // Org: LIGHT < maxLight-3
Off( SENSOR_ROTATION_MOTOR );
dir = 1;
} else if( ROTATION < rotMid ) {
Rev( SENSOR_ROTATION_MOTOR );
On( SENSOR_ROTATION_MOTOR ); // drive to maxLight
while( LIGHT < maxLight-1 ); // Org: LIGHT < maxLight-3
Off( SENSOR_ROTATION_MOTOR );
dir = 2;
}
} while( (dir==1 && ROTATION > rotMid) || (dir==2 && ROTATION < rotMid) );
}
|
|
1 Message in This Thread:
- Entire Thread on One Page:
- Nested:
All | Brief | Compact | Dots
Linear:
All | Brief | Compact
|
|
|
|