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


Conclusion Dans ce chapitre, nous avons vu deux nouvelles structures de contrôle: l'instruction if



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

Conclusion

Dans ce chapitre, nous avons vu deux nouvelles structures de contrôle: l'instruction if et l'instruction while. Il est très important que vous compreniez ce qu'elles font. Il vaudrait donc mieux essayer d'autres exemples avant de continuer.

Les capteurs

Bien sûr vous pouvez connecter des capteurs à la brique NXT pour permettre au robot de réagir avec les évènements extérieurs. Avant que l'on puisse voir comment faire cela, nous devons changer le robot un peu en ajoutant un capteur tactile. Comme auparavant, suivez les instructions Tribot pour construire le pare-chocs avant. Connectez le capteur tactile à l'entrée 1 de la brique NXT.



Attendre après un capteur

Commençons avec un programme très simple dans lequel le robot avance jusqu'à ce qu'il heurte quelque chose. Voici le programme :

task main()

{

SetSensor(IN_1,SENSOR_TOUCH);



OnFwd(OUT_AC, 75);

until (SENSOR_1 == 1);

Off(OUT_AC);

}

Il ya deux lignes importantes ici. La première ligne du programme indique au robot le type de capteur que nous utilisons. IN_1 est le numéro de l'entrée à laquelle nous avons connecté le capteur. Les entrées de capteur sont appelées IN_2IN_3 et IN_4SENSOR_TOUCH indique qu'il s'agit d'un capteur tactile. Pour le capteur de lumière que nous utiliserionsSENSOR_LIGHT. Après avoir précisé le type de capteur, le programme se met en marche. Les deux moteurs et le robot commencent à se déplacer vers l'avant. La déclaration suivante possède une construction très utile. Il attend que la condition entre parenthèses soit vraie. Cette condition indique que la valeur du capteur SENSOR_1 doit être de 1, ce qui signifie que le capteur est pressé. Tant que le capteur n'est pas enfoncé, la valeur est 0. Donc, cette déclaration attend jusqu'à ce que le capteur soit enfoncé. Ensuite, on éteint les moteurs et la tâche est terminée.



Action du capteur tactile

Essayons maintenant de faire éviter les obstacles au robot. Dès qu'il heurtera un objet, il reculera un peu, tournera et continuera sa course. Voici le programme :

task main()

{

SetSensorTouch(IN_1);



OnFwd(OUT_AC, 75);

while (true)

{

if (SENSOR_1 == 1)



{

OnRev(OUT_AC, 75); Wait(300);

OnFwd(OUT_A, 75); Wait(300);

OnFwd(OUT_AC, 75);

}

}

}



Comme dans l'exemple précédent, on indique en premier le type de capteur. Ensuite, le robot commence à avancer. Dans la boucle infinie, le robot testera constamment si le capteur est enfoncé et, si c'est le cas, reculera pendant 300ms, tournera à droite pendant 300ms et avancera à nouveau.

Le capteur de couleur

Outre le capteur tactile, vous possédez un capteur de lumière, un capteur sonore et un capteur numérique à ultrasons. Le capteur de lumière peut être déclenchée afin d'émettre de la lumière ou non, vous permettant de mesurer la quantité de lumière ambiante ou la lumière réfléchie dans une direction particulière. Mesurer la lumière réfléchie est particulièrement utile lors d'un robot de suivre une ligne au sol. C'est ce que nous allons faire dans l'exemple suivant. Pour continuer avec les expériences, il nous faut achever la construction Tribot. Branchez le capteur de lumière sur l'entrée 3, le capteur de sons sur l'entrée 2 et le capteur à ultrasons sur l'entrée 4, comme indiqué dans les instructions.


Nous avons également besoin de la piste noire qui vient avec l'ensemble des pièces du NXT. Le principe de base du suiveur de ligne est d'essayer de rester sur la ligne noire. Se détourner de la ligne si le niveau de luminosité est trop faible (et le capteur est au milieu de la ligne) et se tourner vers la ligne si le capteur est hors de la piste ( et détecte une forte luminosité ). Voici un programme très simple avec une unique valeur seuil de lumière.

#define THRESHOLD 40

task main()

{

SetSensorLight(IN_3);



OnFwd(OUT_AC, 75);

while (true)

{

if (Sensor(IN_3) > THRESHOLD)



{

OnRev(OUT_C, 75);

Wait(100);

until(Sensor(IN_3) <= THRESHOLD);

OnFwd(OUT_AC, 75);

}

}



}

Le programme commence par configurer le port 3, un capteur de lumière. Ensuite, il fait se déplacer le robot vers l'avant et entre dans une boucle infinie. Chaque fois que la valeur de la lumière est plus grande que 40 (nous utilisons ici une constante de telle sorte que cela peut être facilement modifiée, car elle dépend beaucoup de la lumière ambiante) on inverse un moteur et on attend d'être sur la bonne voie.

Comme vous le verrez lorsque vous exécuterez le programme, l'execution n'est pas très lisse. Essayez d'ajouter wait(100) avant la commande until pour faire que le robot bouge mieux. Notez que le programme ne permet pas d'aller dans le sens antihoraire. Pour pouvoir se déplacer en suivant un chemin plus long, il nous faudra un programme plus complexe. Pour lire l'intensité lumineuse ambiante avec les DELs éteintes, configurer le capteur comme suit :

SetSensorType(IN_3,IN_TYPE_LIGHT_INACTIVE);

SetSensorMode(IN_3,IN_MODE_PCTFULLSCALE);

ResetSensor(IN_3);



Le capteur sonore

Nous allons écrire un programme qui attend un grand bruit, et fait avancer le robot jusqu'à ce qu'un autre son soit détecté. Branchez le capteur de sons au port 2, tel que décrit dans les instructions du Tribot.

#define THRESHOLD 40

#define MIC SENSOR_2

task main()

{

SetSensorSound(IN_2);



while(true){

until(MIC > THRESHOLD);

OnFwd(OUT_AC, 75);

Wait(300);

until(MIC > THRESHOLD);

Off(OUT_AC);

Wait(300);

}

}



Nous avons d'abord définir constante THRESHOLD et un alias pour SENSOR_2; dans la tâche principale, il faut configurer le port 2 pour pouvoir lire les données du capteur de sons et ensuite nous entrons dans une boucle infinie. En utilisant l'instruction until, le programme attend que le niveau sonore soit supérieur au seuil que nous avons choisi: à noter que SENSOR_2 n'est pas seulement un nom, mais une macro qui retourne la valeur de son lu à partir du capteur. Si un grand bruit se produit, le robot commence à aller tout droit jusqu'à un autre bruit l'arrête. Les états d'attente ont été insérés pour éviter que le robot ne démarre ou s'arrête instantanément: en effet, le NXT est tellement rapide qu'il ne prend pas de temps à exécuter les lignes entre les until. Si vous commentez le premier et la seconde wait, vous pourrez mieux le comprendre. Une alternative à l'utilisation du wait pour attendre les évènements est la boucle while, il suffit de mettre à l'intérieur des parenthèses une condition toujours complémentaire, par exemple :

while(MIC <= THRESHOLD)

Il n'y a pas grand chose d'autre à savoir sur les capteurs analogiques NXT, il suffit de se rappeler que les capteurs de lumière et du son vous renvoi une valeur entre 0 et 100.

Le capteur à ultrasons

Le capteur à ultrasons fonctionne comme un sonar: grosso modo, il envoie une rafale d'ondes ultrasonores et mesure le temps nécessaire pour que les vagues soient réfléchie par l'objet en face. Il s'agit d'un capteur numérique, ce qui signifie qu'il contient un appareil intégrée pour analyser et transmettre des données. Avec ce nouveau capteur, vous pouvez créer un robot capable de voir et d'éviter un obstacle avant de l'atteindre (comme pour les capteurs de contact).

#define NEAR 15 //cm

task main()

{

SetSensorLowspeed(IN_4);



while(true){

OnFwd(OUT_AC,50);

while(SensorUS(IN_4)>NEAR);

Off(OUT_AC);

OnRev(OUT_C,100);

Wait(800);

}

}

Le programme initialise le port 4 pour lire les données du capteur à ultra son ; puis exécute toujours une boucle où les robots va tout droit jusqu'à ce que quelque chose de plus proche queNEAR cm (15 cm dans notre exemple) soit en vue, il tournera un peu et recommencera à avancer.



Conclusion

Dans ce chapitre, vous avez vu comment travailler avec tous les capteurs inclus dans la boite du NXT. Nous avons également vu comment les commandes while et until sont utiles pour l'utilisation de capteurs. Je vous recommande d'écrire un certain nombre de programmes par vous-même à ce point. Vous avez tous les ingrédients pour donner à vos robots un comportement assez compliqué t: essayer de traduire en NXC le plus simplement possible les programmes du logiciel du CD-ROM.

Les taches et les sous-routines

Jusqu'à maintenant, tous nos programmes se composait d'une seule tâche. Mais les programmes NXC peut avoir de multiples tâches. Il est également possible de mettre des morceaux de code dans les sous-routines que vous pouvez utiliser dans différents endroits de votre programme. L'utilisation de tâches et de sous-routines rend vos programmes plus faciles à comprendre et plus compact. Dans ce chapitre, nous allons examiner les différentes possibilités.



Les taches

Un programme NXC se compose de 255 tâches au plus, chacune d'entre elles a un nom unique. La tâche nommée main doit toujours exister, puisque c'est la première tâche exécutée. Les autres tâches ne seront exécutées que si une tâche en cours d'exécution leur dit d'être exécutée ou si elles sont explicitement appelées dans la principale; la tâche principale doit se terminer avant que les autres puissent commencer. À partir de ce moment, les deux tâches sont exécutées simultanément.

Permettez-moi de vous montrer l'utilisation des tâches. Nous voulons faire un programme dans lequel le robot avance de façon circulaire. Mais lorsqu'il rencontre un obstacle, il doit réagir. Il est difficile de faire cela en une seule tâche, parce que le robot doit faire deux choses en même temps : avancer en rond et de surveiller les capteurs. Il est donc préférable d'utiliser deux tâches pour cela, une tâche pour qu'il se déplace, l'autre pour réagir avec les capteurs. Voici le programme.

mutex moveMutex;

task move_square()

{

while (true)



{

Acquire(moveMutex);

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

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

Release(moveMutex);

}

}



task check_sensors()

{

while (true)



{

if (SENSOR_1 == 1)

{

Acquire(moveMutex);



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

OnFwd(OUT_A, 75); Wait(500);

Release(moveMutex);

}

}



}

task main()

{

Precedes(move_square, check_sensors);



SetSensorTouch(IN_1);

}

La tâche principale définit simplement les types de capteur et planifie le démarrage des deux autres tâches en les ajoutant à la file d'attente du planificateur; après cela, la tâche principale se termine. La tâche move_square fait se déplacer le robot dans un carré indéfiniment. La tâche check_sensors vérifie si le capteur tactile est poussée et, le cas échéant, éloigne robot de l'obstacle. Il est très important de se rappeler que les deux tâches s'exécutent au même moment et cela peut conduire à des résultats inattendus, si les deux tâches essayent d'utiliser les moteurs comme ils sont censés le faire.



Pour éviter ces problèmes, nous avons déclaré un type étrange de variable, mutex (mutual exclusion) : nous ne pouvons agir sur ce type de variables qu'avec les fonction Acquire etRelease.Puis nous écrivons des morceaux de code critique entre ces fonctions, assurant que seuls une tâche à la fois peut avoir un contrôle total sur les moteurs. Ces variables de typemutex sont appelés sémaphores et cette technique de programmation est nommé programmation concurrente; cet argument est décrite en détail dans le chapitre 10.

Les sous-routines

Il arrive parfois que vous ayez besoin d'un même code à de multiples endroits dans votre programme. Dans ce cas, vous pouvez alors mettre ce code dans une "sous-routine" et lui donner un nom. Maintenant, vous pouvez exécuter cette partie de code en appelant simplement son nom dans une tâche. Regardons sur un exemple.

sub turn_around(int pwr)

{

OnRev(OUT_C, pwr); Wait(900);



OnFwd(OUT_AC, pwr);

}

task main()



{

OnFwd(OUT_AC, 75);

Wait(1000);

turn_around(75);

Wait(2000);

turn_around(75);

Wait(1000);

turn_around(75);

Off(OUT_AC);

}

Dans ce programme nous avons défini une sous-routine qui fait tourner le robot autour de son centre. La tâche main appelle la sous-routine 3 fois. Notez que nous l'appelons en écrivant son nom et en lui passant un argument numérique à l'intérieur des parenthèses. Si la sous-routine n'accepte pas d'arguments, il suffit de mettre les parenthèses avec rien dedans. Ça ressemble beaucoup aux commandes que nous avons déjà vu. Le principal avantage des sous-routines est qu'elles ne sont stockées qu'une seule fois dans le NXT et cela libère de la mémoire. Mais lorsque la sous-routine est petite, il peut être préférable d'utilisé les fonction inline à la place. Celles ci ne sont pas copiées séparément mais copiées à chaque endroit où elles sont utilisées. Cela utilise plus de mémoire mais il n'y a pas de limite au nombre de fonctions inline. Elles peuvent être déclarées comme ceci :



inline int Name( Args ) {

//body;

return x*y;

}

Définir et appeler des fonctions inline se fait comme pour les sous-routines. Dans l'exemple suivant, nous utilisons les fonction inline :



inline void turn_around()

{

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



OnFwd(OUT_AC, 75);

}

task main()



{

OnFwd(OUT_AC, 75);

Wait(1000);

turn_around();

Wait(2000);

turn_around();

Wait(1000);

turn_around();

Off(OUT_AC);

}

On peu même rajouter des arguments :



inline void turn_around(int pwr, int turntime)

{

OnRev(OUT_C, pwr);



Wait(turntime);

OnFwd(OUT_AC, pwr);

}

task main()



{

OnFwd(OUT_AC, 75);

Wait(1000);

turn_around(75, 2000);

Wait(2000);

turn_around(75, 500);

Wait(1000);

turn_around(75, 3000);

Off(OUT_AC);

}

Notez que dans les parenthèses derrière le nom de la fonction inline nous spécifions ses arguments. Dans ce cas, nous indiquont que l'argument est un nombre entier (il ya d'autres possibilités) et que son nom est turntime. Quand il ya plusieurs arguments, vous devez les séparer par des virgules. Notez qu'en NXC, sub est comme void; En outre, les fonctions peuvent avoir d'autres types de retour que void, elles peuvent également renvoyer des valeurs entières ou une chaîne de caractère: pour plus de détails, consultez le guide NXC.



Définition de macros

Il ya encore une autre façon de donner un nom à de petits morceaux de code. Vous pouvez définir des macros en NXC (à ne pas confondre avec les macros dans BricxCC). Nous l'avons vu précédemment, il est possible de définir des constantes, en utilisant #define et en leur donnant un nom. Mais en réalité, on peut définir de cette manière n'importe quel morceau de code. Voici le même programme mais en utilisant une macro pour tourner.

#define turn_around \

OnRev(OUT_B, 75); Wait(3400);OnFwd(OUT_AB, 75);

task main()

{

OnFwd(OUT_AB, 75);



Wait(1000);

turn_around;

Wait(2000);

turn_around;

Wait(1000);

turn_around;

Off(OUT_AB);

}

Après l'instruction #define le mot turn_around désigne le texte qui le suit. Maintenant, partout où vous mettrez turn_around, il sera remplacé par le texte de la définition. Notez que le texte doit être sur une seule ligne. (En fait, il existe des moyens de mettre un déclaration #define sur plusieurs lignes, mais ce n'est pas recommandé.)



Les déclarations #define sont en réalité beaucoup plus puissant. Ils peuvent aussi avoir des arguments. Par exemple, nous pouvons mettre le temps à tourner comme argument de la déclaration. Voici un exemple dans lequel nous définissons quatre macros : pour aller de l'avant, se déplacer vers l'arrière, tourner à gauche et à droite. Chacun possède deux arguments : la vitesse et la durée.

#define turn_right(s,t) \

OnFwd(OUT_A, s);OnRev(OUT_B, s);Wait(t);

#define turn_left(s,t) \

OnRev(OUT_A, s);OnFwd(OUT_B, s);Wait(t);

#define forwards(s,t) OnFwd(OUT_AB, s);Wait(t);

#define backwards(s,t) OnRev(OUT_AB, s);Wait(t);

task main()

{

backwards(50,10000);



forwards(50,10000);

turn_left(75,750);

forwards(75,1000);

backwards(75,2000);

forwards(75,1000);

turn_right(75,750);

forwards(30,2000);

Off(OUT_AB);

}

C'est vraiment très utile de définir de telles macros. Cela rend votre code plus compacte et plus lisible. Vous pouvez aussi plus facilement modifier votre code, pour changer la connexion d'un moteur par exemple.



Conclusion

Dans ce chapitre, vous avez vu l'utilisation des tâches, des sous-routines, des fonctions inline et des macros. Elles ont différentes utilités. Les tâches fonctionnent normalement au même moment et s'occupe des choses qui doivent se faire en même temps. Les sous-routines sont utiles pour les grands morceaux de code qui sont utilisés à différents endroits d'une même tâche. Les fonctions inline sont utiles pour les morceaux de code qui sont utilisés à différents endroits d'une même tâche mais cela utilise plus de mémoire. Finalement, les macros sont très utiles pour les petits morceaux de code qui doivent être utilisés à différents endroits. Ces macros peuvent avoir des paramètres de qui les rend très utiles.

Faire de la musique

Le NXT possède un haut-parleur intégré qui peut jouer des sonneries et même des fichiers audio. Ceci est particulièrement utile lorsque vous voulez que le NXT vous dise lorsque quelque chose se passe. Mais il peut aussi être drôle d'avoir un robot qui fasse de la musique ou qui parle pendant qu'il se promène.



À partir d'un fichier sonore

BricxCC possède un utilitaire de conversion de fichier .wav en fichier .rso. Cet utilitaire est accessible via le menu Tools > Sound conversion. Maintenant vous pouvez stocker un fichier .rso dans la mémoire flash du NXT en utilisant un autre accessoire, le navigateur de mémoire du NXT ( Tools > NXT explorer ) et l’exécuter via la commande :

PlayFileEx ( nom_fichier , volume , loop );

Ces arguments sont le nom du fichier son, le volume ( un nombre allant de 0 à 4 ) et loop : ce dernier est à 1 (TRUE) si vous voulez que le morceau soit joué en boucle ou 0 (FALSE) si vous voulez qu'il soit joué qu'une seule fois.

#define TIME 200

#define MAXVOL 7

#define MINVOL 1

#define MIDVOL 3

#define pause_4th Wait(TIME)

#define pause_8th Wait(TIME/2)

#define note_4th \

PlayFileEx("! Click.rso",MIDVOL,FALSE); pause_4th

#define note_8th \

PlayFileEx("! Click.rso",MAXVOL,FALSE); pause_8th

task main()

{

PlayFileEx("! Startup.rso",MINVOL,FALSE);



Wait(2000);

note_4th;

note_8th;

note_8th;

note_4th;

note_4th;

pause_4th;

note_4th;

note_4th;

Wait(100);

}

Ce beau programme joue d'abord la mélodie de démarrage, que vous connaissez peut-être déjà. Les macros sont vraiment utiles dans ce cas pour simplifier la notation dans la tâche principale: essayez de modifier les réglages de volume ou d'ajouter des accents à la mélodie.



Jouer de la musique

Pour jouer une note, vous pouvez utiliser la commande :

PlayToneEx(frequency, duration, volume, loop?)

Qui possède 4 arguments. Le premier est la fréquence en Hertz, le second est la durée en millisecondes, le troisième est le volume et le dernier pour savoir si la musique tourne en boucle. Voici un tableau des fréquences utiles :



SON

3

4

5

6

7

8

9

SI

247

494

988

1976

3951

7902




LA#

233

466

932

1865

3729

7458




LA

220

440

880

1760

3520

7040

14080

SOL#




415

831

1661

3322

6644

13288

SOL




392

784

1568

3136

6272

12544

FA#




370

740

1480

2960

5920

11840

FA




349

698

1397

2794

5588

11176

MI




330

659

1319

2637

5274

10548

RE#




311

622

1245

2489

4978

9956

RE




294

587

1175

2349

4699

9398

DO#




277

554

1109

2217

4435

8870

DO




262

523

1047

2093

4186

8372

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