2. textual user interface nqc (not quite c) c-like programs translated into crx-bytecode composed...

60
2. Textual user 2. Textual user interface NQC interface NQC (Not quite C) (Not quite C) C-like programs translated into CRX-bytecode Composed of: 1. Global variables 2.Task blocks 3. Inline functions 4.subroutines

Post on 20-Dec-2015

220 views

Category:

Documents


2 download

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

Click on RCX2, then OK

2

1

You’ll get this. You should also get another window

If you don’t, press F9 once or twice until you do

File, New gets you a programming window

Copy and paste the text file ‘trusty’ from your email

And save it locally as trusty (a .nqc file)

Click on Compile to compile, and on Download to put it into the RCX.

1

2

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

ArraysArrays• Arrays exist only for RCX2

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 );

SENSORSSENSORS

Sensor Types

Old RCX

NXT brick

Sensor Modes

Sensor Type/Mode Combinations

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.

#define POWER 4

THIS SETS THE POWER LEVEL THAT WILL BE USED FOR MOTORS THAT ARE ON.

trusty.nqc

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

task watcher() {

while (true) {

ONCE STARTED, WATCHER KEEPS ON RUNNING FOR EVER

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?

sources

Owen HollandPeter Marwedel