Utilisation d'un éditeur Nous allons utiliser le logiciel libre Gedit afin d'écrire nos programmes. Si vous êtes sous Debian ( ou debian-like ) et qu'il n'est pas installé, IL suffit de l'installer via cette commande : sudo apt-get install



Yüklə 0,51 Mb.
səhifə4/4
tarix29.10.2017
ölçüsü0,51 Mb.
#19862
1   2   3   4

Un mauvais programme

Considérez le programme suivant. Voici une tâche faisant décrire un carré au robot (comme nous l'avons fait si souvent avant) et la deuxième tâche s'occupe des capteurs tactiles. Lorsqu'un capteur est touché, le robot se déplace un peu vers l'arrière, et fait un virage à 90 degrés.

task check_sensors()

{

while (true)



{

if (SENSOR_1 == 1)

{

OnRev(OUT_AC, 75);



Wait(500);

OnFwd(OUT_A, 75);

Wait(850);

OnFwd(OUT_C, 75);

}

}

}



 

task submain()

{

while (true)



{

OnFwd(OUT_AC, 75); Wait(1000);

OnRev(OUT_C, 75); Wait(500);

}

}



 

task main()

{

SetSensor(IN_1,SENSOR_TOUCH);



Precedes(check_sensors, submain);

}

Ce programme vous semble probablement tout à fait valable. Mais si vous l'exécutez, vous verrez un comportement imprévu. Essayez ce qui suit: faite touche quelque chose au robot pendant qu'il tourne. Il va commencer revenir en arrière, mais se déplace immédiatement vers l'avant à nouveau, atteignant l'obstacle. La raison vient du fait que les tâches peuvent interférer entre elles. Voici ce qu'il se passe. Le robot tourne à droite, voulu par la première tâche, la deuxième tâche est en sommeil. Maintenant, le robot rencontre un obstacle. Il va commencer à reculer, mais à ce moment-là, la tâche principale se réveille et déplace le robot vers l'avant à nouveau : dans l'obstacle. La deuxième tâche esgt en sommeil à ce moment et ne detecte pas la collision. Ce n'est clairement pas le comportement que nous aimerions voir. Le problème est que, tandis que la seconde tâche est en sommeil nous n'avions pas réalisé que la première tâche était encore en marche, et que ses actions interféraient avec les actions de la deuxième tâche.



Sections critiques et les mutex

Voici une façon de résoudre ce problème et de s'assurer qu'à tout moment une seule tâche manipule le robot. Ce fut l'approche, nous avons pris dans un chapitre précédent.

mutex moveMutex;

 

task move_square()



{

while (true)

{

Acquire(moveMutex);



OnFwd(OUT_AC, 75);

Wait(1000);

OnRev(OUT_C, 75);

Wait(850);

Release(moveMutex);

}

}



 

task check_sensors()

{

while (true)



{

if (SENSOR_1 == 1)

{

Acquire(moveMutex);



OnRev(OUT_AC, 75);

Wait(500);

OnFwd(OUT_A, 75);

Wait(850);

Release(moveMutex);

}

}



}

 

task main()



{

SetSensor(IN_1,SENSOR_TOUCH);

Precedes(check_sensors, move_square);

}

Le point crucial est que chacune des tâches check_sensors et move_square peuvent commander les moteurs que si aucune autre tâche n'est en train de les utiliser : cela se fait en utilisant l'instruction Acquire qui attend que la variable d'exclusion mutuelle moveMutex soit libérée avant d'utiliser les moteurs. La réciproque de la commande Acquire est la commandeRelease, qui libère la variable mutex pour que d'autres tâches puissent utiliser la ressource critique, les moteurs dans notre cas. Le code à l'intérieur des Acquire-Release est appelée région critique : critiques signifie que ces ressources partagées sont utilisées. De cette façon, les tâches ne peuvent pas interférer les unes avec les autres.



En utilisant des semaphores

Il existe une alternative aux variable mutex qui est la mise en œuvre explicite des commandes Acquire et Release.

Une technique standard pour résoudre ce problème consiste à utiliser une variable pour indiquer quelle tâche à le contrôle des moteurs. Les autres tâches ne sont pas autorisées à contrôler les moteurs jusqu'à ce que la première tâche l'indique, en utilisant une variable. Une telle variable est souvent appelé un sémaphore. Prennont sem comme étant un sémaphore ( comme un mutex ). Nous supposons que la valeur 0 indique qu'aucune tâche ne contrôle les moteurs (les ressources sont libres). Maintenant, chaque fois qu'une tâche veut faire quelque chose avec les moteurs il exécute les commandes suivantes:

until (sem == 0);

sem = 1; //Acquire(sem);

// Fait quelque chose avec les moteurs

// C'est la région critique

sem = 0; //Release(sem);

Donc, nous attendons d'abord que personne n'utilise les moteurs. Ensuite, nous demandons le contrôle par la mise à 1 de sem. Maintenant, nous pouvons contrôler les moteurs. Quand nous auront fini, nous mettrons sem à 0. Regardez le programme ci-dessus, qui utilise les sémaphores. Lorsque le capteur tactile touche quelque chose, le sémaphore est à 1 et la procédure de recul est en marche. Au cours de cette procédure, la tâche move_square doit attendre. Au moment où le recul est terminé, le sémaphore est remis à 0 et la tâchemove_square peut continuer.

int sem;


task move_square()

{

while (true)



{

until (sem == 0);

sem = 1;

OnFwd(OUT_AC, 75);

sem = 0;

Wait(1000);

until (sem == 0);

sem = 1;


OnRev(OUT_C, 75);

sem = 0;


Wait(850);

}

}



 

task submain()

{

SetSensor(IN_1, SENSOR_TOUCH);



while (true)

{

if (SENSOR_1 == 1)



{

until (sem == 0);

sem = 1;

OnRev(OUT_AC, 75);

Wait(500);

OnFwd(OUT_A, 75);

Wait(850);

sem = 0;


}

}

}



 

task main()

{

sem = 0;


Precedes(move_square, submain);

}

On pourrait dire qu'il n'est pas nécessaire dans move_square de mettre le sémaphore à 1 et ensuite à 0. Pourtant c'est utile. La raison en est que le OnFwd() commande est en fait deux commandes (voir chapitre précédent). Vous ne voulez pas que cette séquence de commande soit interrompue par l'autre tâche.



Les sémaphores sont très utiles et, lorsque vous écrivez des programmes compliqués avec des tâches parallèles, ils sont presque toujours nécessaire. (Il ya encore une petite risque qu'ils échouent. Essayez de comprendre pourquoi.)

Conclusion

Dans ce chapitre, nous avons étudié quelques-uns des problèmes qui peuvent survenir lorsque vous utilisez différentes tâches. Toujours faire très attention aux effets secondaires. Une grande partie du comportement inattendu est dû à cela. Nous avons vu deux différentes façons de résoudre ces problèmes. La première solution est d'arrêter et de redémarrer une tâche afin de s'assurer qu'une seule tâche critique est en cours d'exécution à chaque instant. La deuxième méthode utilise les sémaphores pour contrôler l'exécution des tâches. Cela garantit que, à chaque instant, la partie critique d'une tâche est exécutée.

Communications entre robots

Si vous possédez plus d'un NXT ce chapitre est fait pour vous (mais vous pouvez toujours communiquer des données au PC, si vous n'avez qu'un seul NXT). Les robots peuvent communiquer entre eux via la technologie radio Bluetooth: vous pouvez faire collaborer plusieurs robots (ou les faire se battre), et vous pouvez construire un grand robot complexe au moyen de deux NXTs, de sorte que vous pouvez utiliser six moteurs et huit capteurs.

Pour le bon vieux RCX, c'est simple : il envoie un message infrarouge et tous les robots autour le reçoivent.

Pour le NXT c'est une autre histoire! Tout d'abord, vous devez connecter deux ou plusieurs NXTs (ou NXT PC) via le menu Bluetooth, et alors seulement vous pourez envoyer des messages aux dispositifs connectés.

Le NXT qui démarre la connexion est appelé maître, et peut avoir jusqu'à 3 périphériques esclaves connectés sur les lignes 1,2,3; les esclaves ont le Maître connecté sur la ligne 0. Vous pouvez envoyer des messages à 10 boîtes aux lettres disponibles.

Messagerie maître/esclave

On va voir deux programme, un pour le maître, l'un pour l'esclave. Ces programmes de base vont vous apprendre comment un flux continu de messages rapides peut être géré par un réseau sans fil à deux NXT.

Le programme du maître vérifie d'abord si l'esclave est correctement connecté à la ligne 1 (la constante BT_CONN) à l'aide de la fonction BluetoothStatus(conn); puis construit et envoie des messages avec un préfixe M et un nombre croissant avec SendRemoteString(connqueuestring), tandis que l'on reçoit des messages de l'esclave avecReceiveRemoteString(queueclearstring) et affiche les données.

//MAÎTRE

 

#define BT_CONN 1



#define INBOX 1

#define OUTBOX 5

 

sub BTCheck(int conn){



if (!BluetoothStatus(conn)==NO_ERR){

TextOut(5,LCD_LINE2,"Error");

Wait(1000);

Stop(true);

}

}

 



task main(){

string in, out, iStr;

int i = 0;

BTCheck(BT_CONN); //check slave connection

while(true){

iStr = NumToStr(i);

out = StrCat("M",iStr);

TextOut(10,LCD_LINE1,"Master Test");

TextOut(0,LCD_LINE2,"IN:");

TextOut(0,LCD_LINE4,"OUT:");

ReceiveRemoteString(INBOX, true, in);

SendRemoteString(BT_CONN,OUTBOX,out);

TextOut(10,LCD_LINE3,in);

TextOut(10,LCD_LINE5,out);

Wait(100);

i++;


}

}

Le programme esclave est très similaire, mais utilise SendResponseString(queue,string) au lieu de SendRemoteString parce l'esclave doit pouvoir envoyer des messages seulement à son maître, sur la ligne 0.



//ESCLAVE

 

#define BT_CONN 1



#define INBOX 5

#define OUTBOX 1

 

sub BTCheck(int conn){



if (!BluetoothStatus(conn)==NO_ERR){

TextOut(5,LCD_LINE2,"Error");

Wait(1000);

Stop(true);

}

}

 



task main(){

string in, out, iStr;

int i = 0;

BTCheck(0); //teste la connexion avec l'esclave

while(true){

iStr = NumToStr(i);

out = StrCat("S",iStr);

TextOut(10,LCD_LINE1,"Slave Test");

TextOut(0,LCD_LINE2,"IN:");

TextOut(0,LCD_LINE4,"OUT:");

ReceiveRemoteString(INBOX, true, in);

SendResponseString(OUTBOX,out);

TextOut(10,LCD_LINE3,in);

TextOut(10,LCD_LINE5,out);

Wait(100);

i++;


}

}

Vous remarquerez que si un des programmes s'arrête, l'autre continuera à envoyer des messages avec un nombre croissant, sans savoir que tous les messages envoyés seront perdus, car personne ne l'écoute de l'autre côté. Pour éviter ce problème, nous pourrions prévoir un protocole plus fin, avec accusé de réception.



Envoi de numéros avec accusés

Ici, nous voyons un autre couple de programmes : cette fois, le maître envoie des nombres avec SendRemoteNumber(connqueuenumbre) et cesse d'attendre les accusés de l'esclave; que si l'esclave est à l'écoute et envoi l'accusé, le maître continue en envoyant le message suivant. Les esclaves reçoivent simplement le numéro avecReceiveRemoteNumber(queueclearnumber) et envoie l'accusé avec SendResponseNumber. Vos programmes maître-esclave doivent avoir un code commun pour les accusés de réception, personnelement, je choisis la valeur 0xFF hexadecimale.

Le maître envoie des nombres aléatoires et attend les accusés esclaves; chaque fois qu'il reçoit un accusé de réception avec le bon code, la variable ack doit être réinitialisée, faute de quoi le maître continuera à envoyer sans nouveaux accusés, car la variable est nulle.

L'esclave vérifie en permanence la boîte aux lettres et, si elle n'est pas vide, affiche la valeur lue et envoie un accusé de réception au maître. Au début du programme, j'ai choisi d'envoyer un accusé de réception sans la lecture des messages pour débloquer le maître, en fait, sans cette astuce, si le programme maître est lancé en premier, il serait mort, même si nous lançons un esclave plus tard. De cette façon, les premiers messages peuvent se perdre, mais vous pouvez démarrer des programmes maître et esclave à différents moments, sans risque d'accrochage.



//MAÎTRE

 

#define BT_CONN 1



#define OUTBOX 5

#define INBOX 1

#define CLEARLINE(L) \

TextOut(0,L," ");

 

sub BTCheck(int conn){



if (!BluetoothStatus(conn)==NO_ERR){

TextOut(5,LCD_LINE2,"Error");

Wait(1000);

Stop(true);

}

}

 



task main(){

int ack;


int i;

BTCheck(BT_CONN);

TextOut(10,LCD_LINE1,"Master sending");

while(true){

i = Random(512);

CLEARLINE(LCD_LINE3);

NumOut(5,LCD_LINE3,i);

ack = 0;


SendRemoteNumber(BT_CONN,OUTBOX,i);

until(ack==0xFF) {

until(ReceiveRemoteNumber(INBOX,true,ack) == NO_ERR);

}

Wait(250);



}

}

//ESCLAVE

#define BT_CONN 1

#define OUT_MBOX 1

#define IN_MBOX 5

 

sub BTCheck(int conn){



if (!BluetoothStatus(conn)==NO_ERR){

TextOut(5,LCD_LINE2,"Error");

Wait(1000);

Stop(true);

}

}

 



task main(){

int in;


BTCheck(0);

TextOut(5,LCD_LINE1,"Slave receiving");

SendResponseNumber(OUT_MBOX,0xFF); //unblock master

while(true){

if (ReceiveRemoteNumber(IN_MBOX,true,in) != STAT_MSG_EMPTY_MAILBOX) {

TextOut(0,LCD_LINE3," ");

NumOut(5,LCD_LINE3,in);

SendResponseNumber(OUT_MBOX,0xFF);

}

Wait(10); // pause (optionnelle)



}

}

Envoi de commandes directes

Il ya une autre fonctionnalité intéressante sur la communication Bluetooth: le maître peut contrôler directement ses esclaves.

Dans l'exemple suivant, le maître envoie à l'esclave directement les commandes pour jouer des sons et déplacer un moteur, il n'y a pas besoin d'un programme pour l'esclave, puisque c'est le firmware du NXT esclave qui reçoit et gère les messages!



//MAÎTRE

 

#define BT_CONN 1



#define MOTOR(p,s) RemoteSetOutputState(BT_CONN, p, s, \

OUT_MODE_MOTORON+OUT_MODE_BRAKE+OUT_MODE_REGULATED, \

OUT_REGMODE_SPEED, 0, OUT_RUNSTATE_RUNNING, 0)

 

sub BTCheck(int conn){



if (!BluetoothStatus(conn)==NO_ERR){

TextOut(5,LCD_LINE2,"Error");

Wait(1000);

Stop(true);

}

}

 



task main(){

BTCheck(BT_CONN);

RemotePlayTone(BT_CONN, 4000, 100);

until(BluetoothStatus(BT_CONN)==NO_ERR);

Wait(110);

RemotePlaySoundFile(BT_CONN, "! Click.rso", false);

until(BluetoothStatus(BT_CONN)==NO_ERR);

//Wait(500);

RemoteResetMotorPosition(BT_CONN,OUT_A,true);

until(BluetoothStatus(BT_CONN)==NO_ERR);

MOTOR(OUT_A,100);

Wait(1000);

MOTOR(OUT_A,0);

}

Conclusion

Dans ce chapitre, nous avons étudié quelques-uns des aspects fondamentaux de la communication Bluetooth entre robots: connexion de deux NXTs, envoyer et recevoir des chaînes de caractères, des nombres et des accusés de reception. Ce dernier aspect est très important quand un protocole de communication sécurisé est nécessaire.

Comme fonction supplémentaire, vous avez également appris à envoyer des commandes directement à une brique esclave.

Plus de commandes

Le NXC a un certain nombre de commandes supplémentaires. Dans ce chapitre, nous allons discuter de trois types : l'utilisation de la minuterie, les commandes pour contrôler l'affichage et l'utilisation du système de fichiers NXT.

Temporisateurs

Le NXT a une minuterie qui fonctionne en permanence. Cette minuterie tiques par incrémentations de 1 / 1000 de seconde. Vous pouvez obtenir la valeur actuelle de la minuterie avecCurrentTick(). Voici un exemple de l'utilisation d'une minuterie. Le programme suivant permet de bouger aléatoirement pendant 10 secondes.

task main()

{

long t0, time;



t0 = CurrentTick();

do

{



time = CurrentTick()-t0;

OnFwd(OUT_AC, 75);

Wait(Random(1000));

OnRev(OUT_C, 75);

Wait(Random(1000));

}

while (time<10000);



Off(OUT_AC);

}

Vous pouvez comparer ce programme avec celui donné dans le chapitre IV qui fait exactement la même tâche. Celle avec une minuterie est nettement plus simple.



Les Timers sont très utiles en remplacement du Wait(). Vous pouvez endormir votre programme pour un temps donné en attendant qu'elle atteigne une valeur particulière. Mais vous pouvez aussi réagir sur d'autres événements (par exemple des capteurs) en attendant. Le programme suivant en est un exemple simple. Il permet au robot d'avancer jusqu'à ce que 10 secondes soient passées, ou que le capteur tactile touche quelque chose.

task main()

{

long t3;


SetSensor(IN_1,SENSOR_TOUCH);

t3 = CurrentTick();

OnFwd(OUT_AC, 75);

until ((SENSOR_1 == 1) || ((CurrentTick()-t3) > 10000));

Off(OUT_AC);

}

N'oubliez pas que comme la fonction Wait, les timers fonctionnent à la milliseconde.



Affichage matriciel

La Brique NXT dispose d'un affichage matriciel noir et blanc avec une résolution de 100x64 pixels. Il ya beaucoup de fonctions API pour dessiner des chaînes de caractères, des nombres, points, lignes, rectangles, des cercles, et même des images bitmap (fichiers .ric). L'exemple suivant tente de couvrir tous ces cas. Le pixel numérotées (0,0) est en bas à gauche.

#define X_MAX 99

#define Y_MAX 63

#define X_MID (X_MAX+1)/2

#define Y_MID (Y_MAX+1)/2

 

task main(){



int i = 1234;

TextOut(15,LCD_LINE1,"Display", true);

NumOut(60,LCD_LINE1, i);

PointOut(1,Y_MAX-1);

PointOut(X_MAX-1,Y_MAX-1);

PointOut(1,1);

PointOut(X_MAX-1,1);

Wait(200);

RectOut(5,5,90,50);

Wait(200);

LineOut(5,5,95,55);

Wait(200);

LineOut(5,55,95,5);

Wait(200);

CircleOut(X_MID,Y_MID-2,20);

Wait(800);

ClearScreen();

GraphicOut(30,10,"faceclosed.ric");

Wait(500);

ClearScreen();

GraphicOut(30,10,"faceopen.ric");

Wait(1000);

}

Toutes ces fonctions sont assez explicites, mais maintenant je vais vous décrire leurs paramètres en détail.



- ClearScreen() efface l'écran;

- NumOut(x, y, nombre) vous permet de spécifier les coordonnées et le numéro;

- TextOut(x, y, string) fonctionne comme ci-dessus, mais génère une chaîne de texte

- GraphicOut (x, y, nom de fichier) montre une image bitmap d'un fichier .ric

- CircleOut (x, y, rayon) crée un cercle spécifié par les coordonnées du centre et du rayon;

- LineOut (x1, y1, x2, y2) trace une ligne qui va du point (x1, x2) au point (x2, y2).

- PointOut (x, y) met un point sur ​​l'écran

- RectOut (x, y, largeur, hauteur) dessine un rectangle en bas à gauche avec le vertex (x, y) et avec les dimensions spécifiées;

ResetScreen () réinitialise l'écran.

Système de fichiers

Le NXT peut écrire et lire des fichiers, stockés dans sa mémoire flash. Ainsi, vous pouvez enregistrer un enregistrement de données à partir des données du capteur ou lire des chiffres lors de l'exécution du programme. La seule limite au nombre de fichiers et la dimension est la taille de la mémoire flash. Les fonctions de l'API NXT vous permettent de gérer les fichiers (créer, renommer, supprimer, trouver), vous permettent de lire et d'écrire des chaînes de texte, des nombres et les octets.

Dans le prochain exemple, nous verrons comment créer un fichier, y écrire des chaînes de caractères et le renommer.

Tout d'abord, le programme supprime les fichiers avec les noms que nous allons utiliser : ce n'est pas une bonne habitude (il faut vérifier l'existence de fichiers, le supprimer manuellement ou automatiquement choisir un autre nom pour notre fichier dans lequel nous travaillerons), mais il n'y a pas de problème dans notre simple cas. Il crée notre fichier parCreateFile("Danny.txt"512fileHandle), en précisant le nom, la taille et un lien vers le fichier, où le firmware NXT va écrire un certain nombre pour ses propres utilisations.

Ensuite, il génère des chaînes et les écrit dans le fichier avec WriteLnString(fileHandlestringbytesWritten), où tous les paramètres doivent être des variables. Enfin, le fichier est fermé et renommé. N'oubliez pas: un fichier doit être fermé avant de commencer une autre opération, si vous avez créé un fichier, vous pouvez y écrire, si vous voulez le lire, vous devez le fermer et l'ouvrir avec OpenFileRead(); pour supprimer / renommer, vous devrez le fermer.

#define OK LDR_SUCCESS

 

task main(){



byte fileHandle;

short fileSize;

short bytesWritten;

string read;

string write;

DeleteFile("Danny.txt");

DeleteFile("DannySays.txt");

CreateFile("Danny.txt", 512, fileHandle);

for(int i=2; i<=10; i++ ){

write = "NXT is cool ";

string tmp = NumToStr(i);

write = StrCat(write,tmp," times!");

WriteLnString(fileHandle,write, bytesWritten);

}

CloseFile(fileHandle);



RenameFile("Danny.txt","DannySays.txt");

}

Pour voir le résultat, BricxCC -> Tools -> NXT Explorer, récupérez DannySays.txt et observez. Prêt pour le prochain exemple ! Nous allons créer une tableau de caractères ASCII.



task main(){

byte handle;

if (CreateFile("ASCII.txt", 2048, handle) == NO_ERR) {

for (int i=0; i < 256; i++) {

string s = NumToStr(i);

int slen = StrLen(s);

WriteBytes(handle, s, slen);

WriteLn(handle, i);

}

CloseFile(handle);



}

}

Vraiment simple, ce programme crée le fichier et si aucune erreur n'est survenue, il écrit un nombre entre 0 er 255 (le convertir en chaîne de caractère avant) avec writeBytes (handles,slen), qui est une autre façon d'écrire des chaînes sans retour chariot ; puis il écrit le nombre avec WriteLn (handlevaleur) qui ajoute un retour chariot à la fin. Le résultat, que vous pouvez voir en ouvrant ASCII.txt avec un éditeur de texte, est explicable: le nombre écrit sous forme de chaîne est représentée d'une manière lisible par un humain, alors que le nombre est écrit comme valeur hexadécimale à interpréter et présentée comme un code ASCII.



Deux fonctions importantes restent à être montré: ReadLnString pour lire des chaînes à partir de fichiers et Readln pour lire les nombres.

Maintenant, pour l'exemple de la première fonction : la tâche principale appelle la sous-routine CreateRandomFile qui crée un fichier avec des nombres aléatoires dedans (écrit sous forme de chaînes); vous pouvez commenter cette ligne et utiliser un autre fichier texte créé à la main pour cet exemple.

Dans la sous-routine CreateRandomFile nous produisons une quantité prédéfinie de nombres aléatoires, les convertissons en chaîne de caractères et les écrivons dans le fichier.

Le ReadLnString accepte un lien vers le fichier et une variable de chaîne comme arguments: après l'appel, la chaîne contient une ligne de texte et la fonction retourne un code d'erreur, que nous pouvons utiliser pour savoir si la fin du fichier a été atteinte.

#define FILE_LINES 10

 

sub CreateRandomFile(string fname, int lines){



byte handle;

string s;

int bytesWritten;

DeleteFile(fname);

int fsize = lines*5;

// Crée le fichier

if(CreateFile(fname, fsize, handle) == NO_ERR) {

int n;

repeat(FILE_LINES) {



int n = Random(0xFF);

s = NumToStr(n);

WriteLnString(handle,s,bytesWritten);

}

CloseFile(handle);



}

}

 



task main(){

byte handle;

int fsize;

string buf;

bool eof = false;

CreateRandomFile("rand.txt",FILE_LINES);

if(OpenFileRead("rand.txt", fsize, handle) == NO_ERR)

{

TextOut(10,LCD_LINE2,"Filesize:");



NumOut(65,LCD_LINE2,fsize);

Wait(600);

until (eof == true)

{

if(ReadLnString(handle,buf) != NO_ERR)



eof = true;

ClearScreen();

TextOut(20,LCD_LINE3,buf);

Wait(500);

}

}

CloseFile(handle);



}

Dans le dernier programme, je vais vous montrer comment lire les numéros d'un fichier. Je profite de l'occasion pour vous donner un petit échantillon de la compilation conditionnelle. Au début du code, il ya une définition qui n'est pas utilisé pour une macro ni pour un alias: nous définissons simplement INT.

Ensuite, il ya une déclaration préprocesseur

#ifdef INT

...code...

#endif


qui indique simplement au compilateur de compiler le code entre les deux états si l'INT comme cela a été défini précédemment. Donc, si nous définissons INT, la tâche principale à l'intérieur du premier couplet sera compilé et si LONG est défini au lieu de l'INT, la deuxième version sera compilée.

Cette méthode me permet de montrer dans un seul programme comment les deux types int (16 bits) et long (32 bits) peuvent être lus depuis un fichier en appelant la même fonctionReadln(handleval).

Comme auparavant, il accepte un lien vers le fichier et une variable numérique comme arguments, et retourne un code d'erreur.

La fonction va lire 2 octets à partir du fichier si la variable passée en paramètre est déclarée comme int, et lire 4 octets si la variable est de type long. Les variables de type bool peuvent aussi être lues et écrites de la même façon.

#define INT // INT or LONG

#ifdef INT

 

task main () {



byte handle, time = 0;

int n, fsize,len, i;

int in;

DeleteFile("int.txt");



CreateFile("int.txt",4096,handle);

for (int i = 1000; i<=10000; i+=1000){

WriteLn(handle,i);

}

CloseFile(handle);



OpenFileRead("int.txt",fsize,handle);

until (ReadLn(handle,in)!=NO_ERR){

ClearScreen();

NumOut(30,LCD_LINE5,in);

Wait(500);

}

CloseFile(handle);



}

#endif


 

#ifdef LONG

task main () {

byte handle, time = 0;

int n, fsize,len, i;

long in;


DeleteFile("long.txt");

CreateFile("long.txt",4096,handle);

for (long i = 100000; i<=1000000; i+=50000){

WriteLn(handle,i);

}

CloseFile(handle);



OpenFileRead("long.txt",fsize,handle);

until (ReadLn(handle,in)!=NO_ERR){

ClearScreen();

NumOut(30,LCD_LINE5,in);

Wait(500);

}

CloseFile(handle);



}

#endif


Conclusion

Dans ce dernier chapitre, vous avez rencontré les fonctionnalités avancées offertes par NXT: minuterie haute résolution, affichage matriciel et le système de fichiers.

Conclusion et remarques

Si vous avez tout fait sur ce tutoriel, vous pouvez maintenant un expert en NXC. Si vous n'avez rien fait, il est temps de commencer à travailler. Avec de la créativité dans la conception et dans la programmation vous pouvez faire faire au robots Lego des choses incroyables.

Ce tutoriel ne couvre pas tous les aspects de la BricxCC. Il est recommandé de lire le Guide NXC. En outre, NXC est encore en développement, la future version pourrait intégrer des fonctionnalités supplémentaires. De nombreux concepts de programmation ne sont pas traitées dans ce tutoriel. En particulier, nous n'avons pas songé à comprendre le comportement de robots ou d'autres aspects de l'intelligence artificielle.

Il est également possible de piloter un robot Lego directement à partir d'un PC. Cela vous oblige à écrire un programme dans un langage comme C++, Python ou Java. Il est également possible de laisser un programme en exécution dans le NXT et d’interférer à distance avec celui-ci. Une telle combinaison est très puissante. Si vous êtes intéressé par ce mode de programmation, le meilleur outil est la SDK Fantom et les documents Open Source de la section NXTreme du site Lego Mindstorms.



http://mindstorms.lego.com/Overview/NXTreme.aspx

Le web est une source idéale pour avoir des informations supplémentaires. Certains autres points d'informations importantes sont sur ​​Lugnet, le LEGO Users Group Network (non officielle):



http://www.lugnet.com/robotics/nxt


Yüklə 0,51 Mb.

Dostları ilə paylaş:
1   2   3   4




Verilənlər bazası müəlliflik hüququ ilə müdafiə olunur ©muhaz.org 2024
rəhbərliyinə müraciət

gir | qeydiyyatdan keç
    Ana səhifə


yükləyin