2. textual user interface nqc (not quite c) c-like programs translated into crx-bytecode composed...
Post on 20-Dec-2015
220 views
TRANSCRIPT
2. Textual user 2. Textual user interface NQC (Not interface NQC (Not
quite C)quite C) C-like programs translated into CRX-bytecode Composed of:
1. Global variables
2. Task blocks
3. Inline functions
4. subroutines
C-like programs translated into CRX-bytecode Composed of:
1. Global variables
2. Task blocks
3. Inline functions
4. subroutines
1. You’ll be programming your robot in NQC (Not Quite C).
2. You’ll use the BricxCC (Bricx Control Centre) as your development environment.
3. When you first fire up BricxCC (by double clicking on the BricxCC icon) it looks for the RCX brick.
4. It will find it, because you will have switched it on (using the red On-Off button) and placed it with its infra-red windows facing the IR tower and a few centimetres away from it.
NQC Programming NQC Programming
1. You will get helpful error messages below the program
2. If you can’t sort out the errors by yourself, call Renzo, the GTA
If your program won’t compile…
TasksTaskstask task namename( )( ){{// the task 's code is placed here// the task 's code is placed here}}
1. name: any legal identifier.2. 1 task - named "main" - started when program is run.3. Maximum number of tasks on RCX: 10 4. The body of a task consists of a list of statements.5. Tasks started and stopped: start and stop
statements6.6. StopAllTasksStopAllTasks stops all currently running tasks.
NQC/RCX basics: NQC/RCX basics: MotorsMotors1. Motor connections A, B, and C are known as
OUT_A, OUT_B, and OUT_C
2. You set the direction of a motor by
OnFwd (OUT_A) or OnRev(OUT_B)
3. You set the power of a motor by
SetPower (OUT_A, x) where x runs from 0 to 7
4. You turn a motor off by
Off(OUT_B)
In robotC#pragma config(Motor, motorA, RightMotor,
tmotorNormal, PIDControl, )#pragma config(Motor, motorB, LeftMotor,
tmotorNormal, PIDControl, )//*!!Code automatically generated by 'ROBOTC'
configuration wizard !!*//
void rightTurn(int turnTime){
motor[RightMotor] = -100;motor[LeftMotor] = 100;
wait10Msec(turnTime);}
void leftTurn(int turnTime){
motor[RightMotor] = 100;motor[LeftMotor] = -100;
wait10Msec(turnTime);}
sub turn_around(){ OnRev(OUT_C); Wait(400); OnFwd(OUT_AOUT_A+OUT_COUT_C);}
This in NQC
In robotC#pragma config(Motor, motorA, RightMotor, tmotorNormal, PIDControl, )#pragma config(Motor, motorB, LeftMotor, tmotorNormal, PIDControl, )//*!!Code automatically generated by 'ROBOTC' configuration wizard !!*//
void rightTurn(int turnTime){
motor[RightMotor] = -100;motor[LeftMotor] = 100;
wait10Msec(turnTime);}
void leftTurn(int turnTime){
motor[RightMotor] = 100;motor[LeftMotor] = -100;
wait10Msec(turnTime);}
task main(){
motor[RightMotor] = 100;motor[LeftMotor] = 100;
wait10Msec(100);
rightTurn(20);
motor[RightMotor] = 100;motor[LeftMotor] = 100;
wait10Msec(100);
leftTurn(20);
motor[RightMotor] = 100;motor[LeftMotor] = 100;
wait10Msec(100);
StopAllTasks();}
NQC/RCX basics: NQC/RCX basics: SubroutinesSubroutines1. There are several ways of avoiding having to
write out long strings of repetitive chunks of code.
2. One is to use subroutines.
3. The format of a subroutine is:
sub subroutinename ( ) {code goes here}
4. And you call it in the main body of your code by
subroutinename ( );
5. (Semicolons are used as separators for expressions etc.)
SubroutinesSubroutinessub turn_around(){ OnRev(OUT_C); Wait(400); OnFwd(OUT_A+OUT_C);}
task main(){ OnFwd(OUT_A+OUT_C); Wait(100); turn_around(); Wait(200); turn_around(); Wait(100); turn_around(); Off(OUT_A+OUT_C);}c
Subroutines1. Subroutines allow a single copy of some code to be
shared between several different callers (space efficient).
2. Restrictions:1. First of all, subroutines cannot use any arguments.2. A subroutine cannot call another subroutine.3. Maximum number of subroutines: 8 for the RCX4. If calling from multiple tasks: no local variables or
perform calculations that require temporary variables (this restriction is lifted for the Scout and RCX2).
NQC/RCX basics: NQC/RCX basics: Control structuresControl structures
1. while (true) {stuff}
will execute stuff forever.
2. if (condition) do_something_simple
will do_something_simple if the condition is true
3. if (condition) do_something_simple
else do_something_else
will do_something_else if the condition is not true
Control structures– If-statements
if (condition) consequenceif (condition) consequence else alternative
– While-statementswhile (condition) body
– Repeat-statements repeat (expression) body
– Switch-statementswitch (expression) body
– Until-macro# define until (c) while (! (c ))
Inline function, call by referenceInline function, call by referencevoid turn_around(int turntime){ OnRev(OUT_C); Wait(turntime); OnFwd(OUT_A+OUT_C); }task main(){ OnFwd(OUT_A+OUT_C); Wait(100); turn_around(200); Wait(200); turn_around(50); Wait(100); turn_around(300); Off(OUT_A+OUT_C); }
task main(){ int count=0; while (count<=5)
{ PlaySound(SOUND_CLICK);
Wait(count*20); increment(count); }}void increment(int& n){ n++; }
task main(){ int count=0; while (count<=5)
{ PlaySound(SOUND_CLICK);
Wait(count*20); increment(count); }}void increment(int& n){ n++; }
(Inline) Functions• void name( argument_list )• { // body of the function }• Functions cannot return a value; void is related to C• Argument list: empty, or ≥ 1 argument definitions.• Arguments: type followed by its name.• All values are 16 bit signed integers.
• 4 different argument classes4 different argument classes:
Type Meaning Restriction
int Pass by value None
int& Pass by reference Only variables may be used
const int Pass by value Only constant may be used
const int& Pass by reference Function cannot modify argument
Playing preprogrammed sounds & tones
task music(){ while (true) { PlayTone(262,40); Wait(50); PlayTone(294,40); Wait(50); PlayTone(330,40); Wait(50); PlayTone(294,40); Wait(50); } }task main(){ start music; while(true) { OnFwd(OUT_A+OUT_C); Wait(300); OnRev(OUT_A+OUT_C); Wait(300); } }
task main(){ PlaySound(0);
Wait(100); PlaySound(1); Wait(100); PlaySound(2); Wait(100); PlaySound(3); Wait(100); PlaySound(4); Wait(100); PlaySound(5); Wait(100);}
task main(){ PlaySound(0);
Wait(100); PlaySound(1); Wait(100); PlaySound(2); Wait(100); PlaySound(3); Wait(100); PlaySound(4); Wait(100); PlaySound(5); Wait(100);}
VariablesVariables• All variables of the same type: 16 bit signed integers.• Declarations: int variable[=initial value] [, variable [=initial value]] ;
• Examples:• int x ; // declare x• int y, z ; // declare y and z• int a =1, b ; // declare a and b, initialize a to 1
– Global variables: declared at the program scope;Used within tasks, functions, subroutines.Used within tasks, functions, subroutines. Max: 32
– Local variables: within tasks, functions, and sometimes within subroutines. Max: 0 @ RCX, 16 @RCX2
– Local variables may be declared in a compound statement, following a {
All variables are integers. You have to declare them, otherwise the compiler will moan.
int thing;
at the beginning of your program will let you use the integer variable thing anywhere.
If you declare it within some curly brackets (as part of an expression or subroutine etc.) it won’t work if you try to use it outside the brackets (and the compiler will complain).
NQC/RCX basics: Variables
You can give constants meaningful names instead of numbers by defining them at the start of your program:
#define MONKEY_SCORE 25
means you can write MONKEY_SCORE in your code instead of just 25, and so you will be able to distinguish it from all the other constants that might be 25 – for example, SLAMMER_RECORD
NQC/RCX basics: Constants
AssignmentsAssignments• Syntax:
Variable operator expression• Operators:• = Set variable to expression• += Add expression to variable• -= Subtract expression from variable• *= Multiple variable by expression• /= Divide variable by expression• &= Bitwise AND expression into variable• |= Bitwise OR expression into variable• ||= Set variable to absolute value of expression• +-= Set variable to sign (-1,+1,0) of expression
Built-in API • SetPower(outputs, power) Function
1. Sets the power level of the specified outputs.2. Power should result in a value between 0 and 7.3. OUT_LOW, OUT_HALF, OUT_FULL may also be used.
Examples:• SetPower( OUT_A, OUT _FULL) ; // A full power• SetPower( OUT_B, x );
• OnFwd(outputs) Function1. Set outputs to forward direction and turn them on.2. Outputs is one or more of OUT_A, OUT_B, and OUT_C added
together.
• Example: OnFwd (OUT_A );
Setting Sensor Type and Mode
• SetSensor(sensor, configuration) – Set the type and mode to the specified configuration
(constant containing both type and mode info).• Example:• SetSensor (SENSOR_1, SENSOR_TOUCH) ;
• SetSensorType(sensor, type)– Set type (one of the predefined sensor type constants).– Example:
SetSensorType(SENSOR_1, SENSOR_TYPE _TOUCH );
• SetSensorMode(sensor, mode)– Set mode (one of the predefined sensor mode constants)
Optional slope parameter for Boolean conversion.
Reading out sensors, Wait• SensorValue(n)
– Returns the processed sensor reading for sensor n, where n is 0, 1, or 2. This is the same value that is returned by the sensor names
• (e.g. SENSOR_1).– Example:
x = SensorValue(0); // readsensor_1
• Wait(time)• Make a task sleep for specified amount of time (in 1/100 s).
Argument may be an expression or a constant.• Wait(100); // wait 1 second• Wait(Random (100)); // wait random time up to 1 second
• Wait(time)• Make a task sleep for specified amount of time (in 1/100 s).
Argument may be an expression or a constant.• Wait(100); // wait 1 second• Wait(Random (100)); // wait random time up to 1 second
For more information refer to the NQC programmers manual
Example of motor control in NQCExample of motor control in NQC
// speed.nqc -- sets motor power, goes forward, waits, // goes backwardstask main( ){ SetPower(OUT_A+OUT_C,2); OnFwd(OUT_A+OUT_C); Wait(400); OnRev(OUT_A+OUT_C); Wait(400); Off(OUT_A+OUT_C);}
1. sets motor power, 2. goes forward, waits, 3. goes backwards
Robots moves in a SpiralRobots moves in a Spiral// spiral.nqc -- Uses repeat & variables to make robot// spiral.nqc -- Uses repeat & variables to make robot
// move in a spiral// move in a spiral#define TURN_TIME 100int move_time; // define a variabletask main()task main(){ move_time = 20; // set the initial value repeat(50) { OnFwdOnFwd(OUT_A+OUT_C); Wait(move_time); // use the variable for sleepinguse the variable for sleeping OnRevOnRev(OUT_C); Wait(TURN_TIME); move_time += 5; // increase the variableincrease the variable } Off(OUT_A+OUT_C); }
Use of touch sensorstouch sensors
// Use of touch sensorstask main(){ SetSensor(SENSOR_1,SENSOR_TOUCH); OnFwd(OUT_A+OUT_C); while (true) { if (SENSOR_1 == 1) { OnRev(OUT_A+OUT_C); Wait(30); OnFwd(OUT_A); Wait(30); OnFwd(OUT_A+OUT_C); } }}
Declare that SENSOR_1SENSOR_1 is touch sensor
Go forward with speed OUT_A + OUT_C
Go backward with speed OUT_A + OUT_C
Use of light sensor
// Use of a light sensor to make robot go forward until// it "sees" black, then turn until it's over white#define THRESHOLD 37task main(){ SetSensor(SENSOR_2,SENSOR_LIGHT); OnFwd(OUT_A+OUT_C); while (true) { if (SENSOR_2 < THRESHOLD) { OnRev(OUT_C); Wait(10); until (SENSOR_2 >= THRESHOLD); OnFwd(OUT_A+OUT_C); } } }
NQC/RCX basics: Sensors1. Sensor connections 1, 2, and 3 are known as
SENSOR_1, SENSOR_2, and SENSOR_3
2. You have to tell each sensor connection what sort of sensor is plugged into it.
3. For the light sensor, it’s just a matter of:
4. SetSensor (SENSOR_2, SENSOR_LIGHT)
NQC/RCX basics: Tasks1. NQC can run several tasks at the same time.
(Unfortunately you have to be careful to ensure that tasks do not conflict, especially over resources.)
2. The format of a task is:
task taskname( ) {task instructions etc go here}
3. Every program must contain a task called main:
task ( ) main {stuff}
TaskingTaskingtask main(){ SetSensor(SENSOR_1,SENSOR_TOUCH); start check_sensors; start move_square; }
task move_square(){ while (true) { OnFwd(OUT_A+OUT_C); Wait(100); OnRev(OUT_C); Wait(85); } }
task check_sensors(){ while (true) { if (SENSOR_1 == 1) { stop move_square; OnRev(OUT_A+OUT_C); Wait(50); OnFwd(OUT_A); Wait(85); start move_square; } } }
Starts two tasks described below
MacrosMacros#define turn_right(s,t)
SetPower(OUT_A+OUT_C,s);OnFwd(OUT_A);OnRev(OUT_C);Wait(t);#define turn_left(s,t)
SetPower(OUT_A+OUT_C,s);OnRev(OUT_A);OnFwd(OUT_C);Wait(t);#define forwards(s,t)
SetPower(OUT_A+OUT_C,s);OnFwd(OUT_A+OUT_C);Wait(t);#define backwards(s,t)
SetPower(OUT_A+OUT_C,s);OnRev(OUT_A+OUT_C);Wait(t);task main()task main(){ forwards(1,200); turn_left(7,85); forwards(4,100); backwards(1,200); forwards(7,100); turn_right(4,85); forwards(1,200); Off(OUT_A+OUT_C);}
#define turn_right(s,t) SetPower(OUT_A+OUT_C,s);OnFwd(OUT_A);OnRev(OUT_C);Wait(t);
#define turn_left(s,t) SetPower(OUT_A+OUT_C,s);OnRev(OUT_A);OnFwd(OUT_C);Wait(t);
#define forwards(s,t) SetPower(OUT_A+OUT_C,s);OnFwd(OUT_A+OUT_C);Wait(t);
#define backwards(s,t) SetPower(OUT_A+OUT_C,s);OnRev(OUT_A+OUT_C);Wait(t);
task main()task main(){ forwards(1,200); turn_left(7,85); forwards(4,100); backwards(1,200); forwards(7,100); turn_right(4,85); forwards(1,200); Off(OUT_A+OUT_C);}
It’s straight from the Knudsen book.
We’ll skip through some basics, and then go through the program.
EXAMPLE: The EXAMPLE: The trusty.nqc program trusty.nqc program
int state;
#define BOTH_ON 3
#define LEFT_ON 1
#define RIGHT_ON 2
#define BOTH_OFF 0
#define INDETERMINATE 255
#define DARK2 35
#define LIGHT2 40
#define DARK3 40
#define LIGHT3 45
#define POWER 4
trusty.nqc
int state;
THIS IS THE DECLARATION OF THE VARIABLE WE WILL USE TO REPRESENT ALL THE DIFFERENT MEANINGFUL COMBINATIONS OF SENSOR STATES
trusty.nqc
#define BOTH_ON 3
#define LEFT_ON 1
#define RIGHT_ON 2
#define BOTH_OFF 0
#define INDETERMINATE 255
THESE ARE THE VALUES THE VARIABLE state CAN TAKE.
BOTH_ON MEANS BOTH SENSORS ON THE TRACK, ETC.
INDETERMINATE MEANS AT LEAST ONE SENSOR IS ON THE BORDERLINE
trusty.nqc
#define DARK2 35
#define LIGHT2 40
#define DARK3 40
#define LIGHT3 45
THESE ARE THE SENSOR INPUT VALUES FOR DECIDING WHETHER A SENSOR IS ON OR OFF THE LINE, OR ON THE BORDERLINE
trusty.nqc
Sensor tip1. If the sensor port is correctly configured, you can read
the value of a sensor directly from the LCD display on the RCX.
2. Press VIEW.
1. You will see a little ^ pointing to input 1.
2. The number on the LCD will be the current input of the sensor connected to input 1.
3. Press VIEW again.
1. The ^ will move round one place to input 2.
4. Keep on pressing and it will go 3, A, B, C, and then out of VIEW mode.
task main() {
initialize();
while (true) {
if (state == BOTH_ON)
OnFwd(OUT_A + OUT_C);
else if (state == LEFT_ON) {
Off(OUT_A);
OnFwd(OUT_C);
}
else if (state == RIGHT_ON) {
Off(OUT_C);
OnFwd(OUT_A);
}
}
}
trusty.nqc
task main() {
initialize();
while (true) {
CODE HERE
}
}
THIS STARTS THE MAIN TASK, INITIALIZES EVERYTHING USING THE SUBROUTINE INITIALIZE, AND EXECUTES THE CODE IN THE MIDDLE
trusty.nqc
if (state = = BOTH_ON)
OnFwd(OUT_A + OUT_C);
else if (state = = LEFT_ON) {
Off(OUT_A);
OnFwd(OUT_C);
}
else if (state = = RIGHT_ON) {
Off(OUT_C);
OnFwd(OUT_A);
THIS GOES FORWARD FOR BOTH_ON, TURNS LEFT FOR LEFT_ON, AND TURNS RIGHT FOR RIGHT_ON
trusty.nqc
sub initialize()sub initialize() {
SetSensor (SENSOR_2, SENSOR_LIGHT);
SetSensor (SENSOR_3, SENSOR_LIGHT);
SetPower (OUT_A + OUT_C, POWER);
OnFwd(OUT_A + OUT_C);
start watcher;
}
THIS IS THE SUBROUTINE initialize. IT SETS THE SENSOR INPUTS CORRECTLY, STARTS THE ROBOT GOING FORWARD, AND STARTS THE TASK watcher.
trusty.nqc
task watcher() {
while (true) {
if (SENSOR_2 < DARK2) {
if (SENSOR_3 < DARK3) state = BOTH_ON;
else if (SENSOR_3 > LIGHT3) state = LEFT_ON;
else state = INDETERMINATE;
}
else if (SENSOR_2 > LIGHT2) {
if (SENSOR_3 < DARK3) state = RIGHT_ON;
else if (SENSOR_3 > LIGHT3) state = BOTH_OFF;
else state = INDETERMINATE;
}
else state = INDETERMINATE;
}
}
trusty.nqc
if (SENSOR_2 < DARK2) {
if (SENSOR_3 < DARK3) state = BOTH_ON;
else if (SENSOR_3 > LIGHT3) state = LEFT_ON;
else state = INDETERMINATE;
IF BOTH SENSORS ARE BELOW THEIR INDIVIDUAL DARK THRESHOLD, state IS SET TO BOTH_ON.
IF THE SENSOR ON THE LEFT IS DARK, AND THE SENSOR ON THE RIGHT IS ABOVE ITS LIGHT THRESHOLD, state IS SET TO LEFT_ON.
IF THE SENSOR ON THE LEFT IS DARK, AND THE SENSOR ON THE RIGHT IS BETWEEN ITS LIGHT AND DARK THRESHOLD, state IS SET TO INDETERMINATE
trusty.nqc
else if (SENSOR_2 > LIGHT2) {
if (SENSOR_3 < DARK3) state = RIGHT_ON;
else if (SENSOR_3 > LIGHT3) state = BOTH_OFF;
else state = INDETERMINATE;
THIS SORTS OUT RIGHT_ON AND BOTH_OFF, AND ANOTHER KIND OF INDETERMINATE
trusty.nqc
else state = INDETERMINATE;
AND THIS CATCHES THE CASE WHERE BOTH SENSORS ARE BETWEEN THRESHOLDS
THAT’S ALL YOU NEED – OFF YOU GO…
trusty.nqc
Books:
Core Lego Mindstorms Programming by Brian Bagnold
Good intro to Mindstorms and to LeJos
Web:
Too many sites to list. Just Google any mixture of mindstorms, lego, robot, sensors, java, nqc, rcx. Lots of good stuff, and most sites have links to lots of others.
How can I find out more? How can I find out more?