Comment envoyer la distance à mon robot ?

  • Auteur de la discussion 25azerty25
  • Date de début

25azerty25

Nouveau membre
Bonjour,
Je suis en train de faire un programme sous LabVIEW qui doit communiquer avec une brique Lego Mindstorms (brique qui sert à contrôler un robot fait en Lego) (La communication labview/brique se fait par infrarouges). Cette brique contient un programme esclave (programmé en C). Pour communiquer avec cette brique, je dois lui envoyer des ordres sous forme de chaînes de caractères depuis Labview. A chaque chaîne de caractères reçue correspond une partie du programme à exécuter (le programme esclave interprète les infos envoyées par Labview).
Explications : le programme esclave est fait de la manière suivante (en gros):

Code:
#define  toto "AVANCE" 		/* toto est le nom de la chaîne lorsque la brique reçoit l'orde AVANCE depuis labview */
#define  tata "STOP"
int variable;

...blablabla...

if ( strcmp(msg, toto) == 0 )  		/* là on test si le message reçu est toto (ou AVANCE c'est pareil) */
 {
 variable = 0;
 }

					
int main (void)			/* programme principal */
{

	if (variable == 0)
	{
 le robot va en avant;
	}
}

Bon, ça c'est pas un problème.
Maintenant je voudrais envoyer non seulement des ordres (avance, stop, tourne à droite,…) mais aussi des consignes (ex: stop quand distance parcourue = 15mm). Le problème est que la brique ne doit recevoir que des chaînes de caractères. Faudrait donc que je convertisse cette distance en chaîne (sous labview). Le problème c'est que je n'ai pas envie de déclarer une chaîne (dans mon programme esclave) pour chaque distance à parcourir…

Comme solution, je pensais à ça : je décompose la distance en unités, dizaines, centaines… je converti les unités en chaîne (ex: 0=A, 1=B,…,9=I) que j'envoie à la brique. Le programme esclave se charge ensuite de reconvertir cette chaîne en nombre décimal. Idem pour les dizaines et centaines. Ensuite je fais la somme et je retrouve ma distance à parcourir.

Que pensez vous de cette idée ?
Y'a pas moins farfelu ?

Merci
 

zeb

Modérateur
Ah ça, pour être farfelu, c'est farfelu !
C'est quoi cette idée de vouloir définir toutes les distances en chaîne ?

___________________________________


Il te faudair plutôt définir un mini-langage. Avec un verbe et un complément :

> AVANCE
> AVANCE 15
> STOP
> TOURNE GAUCHE
> TOURNE 30

Le verbe AVANCE attend un paramètre optionnel, la distance en mm. C'est un nombre entier positif. Si pas de paramètre, la distance est égale à l'infini.

Le verbe STOP n'attend aucun paramètre. On s'en fout donc.

Le verbe TOURNE attend un paramètre obligatoire. Soit GAUCHE/DROITE, soit un angle en degré. GAUCHE signifie 90°, DROITE signifi -90°. C'est donc un entier entre -180 et 180.

etc.

Bref, on peut dire que l'interface général, c'est un verbe et un nombre entier signé.

Du côté Labview :
Code:
sprintf(ordre, "AVANCE %d\n", distance)

Du côté Lego :
Code:
int decodage (int* verbe, int* nombre)
{
	char* VERBE[] = {"AVANCE", "STOP", "TOURNE"};
	char* PARAM[] = {"GAUCHE", "DROITE"};
	
	int i;
	char* param;
	
	// Quel verbe :
	for (i=0; i<3; i++)
	{
		// Un verbe tout seul ou suivi d'un espace.
		if (strncmp(msg, VERBE[i], strlen(VERBE[i])) == 0 &&
		    (msg[strlen(VERBE[i])] == '\0' || msg[strlen(VERBE[i])] == ' ' ))
		{
			verbe = i;
			break;
		}
	}
	
	if (verbe == -1)
	{
		// Pas trouvé !
		return -1;
	}
	else
	{
		param = msg+strlen(VERBE[i]);
		while (param[0] == ' ') param = param++;
	}
	
	if (verbe == 0)
	{
		char* error;
	
		if (param[0] == '\0')
			nombre = 10000; // 10 mètre !
		else
		{
			nombre = strtol(param, error, 10);
			if (error != NULL)
				return -1; // On demande un nombre !!!
			return 0; // Ok.
		}
	}

...
}

int main()
{
	int verbe, nombre;
	
	if (decodage(verbe, nombre)==0)
	{
		if (verbe==0)
			// Le robot va en avant de nombre millimètre.
	}
	else
	{
		// Le robot devient tout rouge parce qu'il n'a rien compris !
	}
}
 

25azerty25

Nouveau membre
OK OK, merci.
Mais y'a des passages que je ne comprends pas.
A la ligne 13:
if (stricmp(msg, VERBE, strlen(VERBE))

on compare 3 chaînes à la fois ? seulement strlen(VERBE) c'est pas une chaîne...

A la ligne 14:
msg[strlen(VERBE)

je ne comprends pas la structure, je ne vois pas ce qu'on doit obtenir: un chiffre, une chaîne ?

A la ligne 28:
param = msg+strlen(VERBE);

Même question. On additionne une chaîne et une longueur de chaîne... :heink:
 

zeb

Modérateur
Evidemment que tu ne comprends pas, le i et le n sont tellement proches sur mon clavier que je me suis trompé [:patch]
Il faut donc lire strncmp bien sûr. ;)

Eh ben. Tu en as des choses à apprendre en C !
T'es bien tombé, va ;)

_________________________________


Il n'y a pas de chaîne de caractères en C.
C'est comme ça, pis c'est tout. (c) PL

Bon, on se débrouille autrement. Avec des tableaux de caractères.

Les tableaux :

On les déclare comme ça :
<type élémentaire> <nom du tableau> [ <taille du tableau> ];
Code:
char chaine[12];
int indices[4];

Et on dit que <nom du tableau> est de type <type élémentaire>[].
chaine est un char[].
indices est un int[].

On accède au contenu d'un des éléments du tableau comme ça :
<nom du tableau> [ <indice de l'élément> -1 ]
Cet élément est de type <type élémentaire>

En mémoire cela se passe comme ça : une suite de <taille du tableau> de <type élémentaire>.
Pour nos deux exemples :
[fixed]
chaine --> +-+-+-+-+-+-+-+-+-+-+-+-+
| | | | | | | | | | | | |
+-+-+-+-+-+-+-+-+-+-+-+-+

indice --> +-------+-------+-------+-------+
| | | | |
+-------+-------+-------+-------+
[/fixed]
Et oui, un char, c'est un octet, un int, c'est 4 octets (sur un système 32 bits).

Maintenant, pour fixer les choses, on va mettre du contenu dans nos cases.

Code:
chaine[0] = '2';
chaine[1] = '5';
chaine[2] = 'a';
chaine[3] = 'z';
chaine[4] = 'e';
chaine[5] = 'r';
chaine[6] = 't';
chaine[7] = 'y';
chaine[8] = '2';
chaine[9] = '5';
indice[0] = 10;
indice[1] = 12;
indice[2] = 14;
indice[3] = 16;
[fixed]
chaine --> +-+-+-+-+-+-+-+-+-+-+-+-+
|2|5|a|z|e|r|t|y|2|5| | |
+-+-+-+-+-+-+-+-+-+-+-+-+

indice --> +-------+-------+-------+-------+
| 10| 12| 14| 16|
+-------+-------+-------+-------+
[/fixed]
Pour savoir ou s'arrête le texte, on ajoute un zéro à la fin de chaque chaîne.
Un zéro au sens code, pas au sens caractère, chiffre.
Le chiffre zéro s'écrit '0' (char) ou 48 (code).
Le nombre zéro s'écrit '\0' (char) ou 0 (code).
Code:
chaine[10] = '\0';
[fixed]
chaine --> +-+-+-+-+-+-+-+-+-+-+--+-+
|2|5|a|z|e|r|t|y|2|5|\0| |
+-+-+-+-+-+-+-+-+-+-+--+-+
[/fixed]

C'est cool, non ? Ben non, c'est super pénible. :(
Alors on a inventé des fonctions pour gérer les chaînes de caractères, mais le principe est le même.

Code:
strcpy(chaine, "25azerty25");
Voilà, comme ça c'est plus simple. :)
Par contre, rien pour les autres types, seuls les char[] ont un traitement de faveur.

zeb> A quoi est égal chaine ?
25a> chaine est égal à "25azerty25" !
zeb> Faux. chaine est l'adresse où par ailleurs on est allé mettre "25azerty25". Il se trouve que pour les fonctions str*, c'est pareil. Mais pas pour le C.

chaine + 1 est donc l'adresse de chaine plus une case.
La case de chaine étant sur un octet (char), la case de indice étant de 4 octets (int), voilà où sont chaine + 1 et indice + 1 :
[fixed]
chaine + 1 ---+
v
+-+-+-+-+-+-+-+-+-+-+-+-+
|2|5|a|z|e|r|t|y|2|5| | |
+-+-+-+-+-+-+-+-+-+-+-+-+

indice + 1 ---------+
v
+-------+-------+-------+-------+
| 10| 12| 14| 16|
+-------+-------+-------+-------+
[/fixed]

Mais ce qui est important, maintenant, c'est de connaître les types de nos variables :
chaine est de type char[].
chaine[1] est de type char.
chaine+1 est de type char[].

Les fonctions str* attendent des paramètres de type char[], on va donc leur en fournir.


Pour finir, il faut savoir que <type>[] et <type>* sont équivalents sémantiquement.

_________________________________


Pour comprendre sur un cas simple :
Code:
int main()
{
	char chaine[] = "25azerty25";

	printf("chaine     : %s\n", chaine    );
	printf("chaine[0]  : %c\n", chaine[0] );
	printf("chaine + 2 : %s\n", chaine + 2);
	printf("chaine[2]  : %c\n", chaine[2] );

	return 0;
}

_________________________________


Code:
char* VERBE[] ...
msg[strlen(VERBE[i])
Q. De quel type est VERBE ?
A. De type char*[] ! Ou encore char[][].

Q. De quel type est VERBE[] ?
A. De type char* (=char[]).

Donc strlen(VERBE) renvoie bien la longueur de la chaîne VERBE.

Q. De quel type sont msg et msg[] ?
A. De type char*/char[] et de type char, respectivement.
Donc msg[strlen(VERBE) est un caractère (char).

VERBE[0] est donc l'adresse du premier mot du tableau de tableaux de caractères VERBE [:pt1cable]
On y trouve "AVANCE".

Le message peut être "AVANCE", ou "AVANCE 1234" :

En mémoire :
(J'ai remplacé '\0' par ° pour tenir sur un caractère.)
[fixed]
VERBE --> AVANCE°
STOP°
TOURNE°

+------ Qu'il y a-t-il là ?
v
msg0 ----> N'importe quoi°
msg1 ----> AVANCE°
msg2 ----> AVANCER TOUT DROIT°
msg3 ----> AVANCE 1234°
[/fixed]

Code:
if (strncmp(msg, VERBE[i], strlen(VERBE[i])) == 0 && 
          (msg[strlen(VERBE[i])] == '\0' || msg[strlen(VERBE[i])] == ' ' ))

Donc, je cherche à comparer msg et VERBE, sur toute la longueur de VERBE mais seulement sur les premiers caractères de msg.
Je prends donc la longueur de VERBE et je compare msg et VERBE sur cette longueur.
msg0 ne convient donc pas.
Juste après je regarde si la phrase est finie ('\0') ou s'il y a un espace. S'il y a autre chose, cela ne n'intéresse pas.
msg2 ne convient donc pas puisque R n'est ni la fin de phrase, ni un espace.

Est-ce plus clair pour les lignes 13 et 14 ?


Passons maintenant au paramètre
[fixed]
msg -------+ +-------- paramètre
v v
AVANCE 1234°
^
+--------- msg+6
[/fixed]
On a dit qu'on commençais par le verbe. Donc pas la peine de le chercher, il est au début, c'est à dire à l'adresse msg.
Mais où est le paramètre ? Il est plus loin.
Normalement, on devrait le trouver à l'adresse msg en se décalant de la longueur du verbe plus de l'espace.

Je veux non pas le premier caractère du paramètre, mais l'adresse du début de paramètre.
Je veux paramètre de type char[].
Comme vu plus haut, msg est de type char[], donc en décalant msg de la taille du verbe je devrais tomber sur le premier espace en restant de type char[].
Code:
param = msg+strlen(VERBE[i]);
La ligne 29 me fait me décaler d'autant d'espace qu'il y a. Comme ça, tu peux en mettre plusieurs ;)

Est-ce plus clair pour la ligne 28 ?
 

25azerty25

Nouveau membre
OK, j'ai réussi à faire ce que je voulais : extraire les données numériques d'une chaine de caractères.

Merci zeb pour ton aide.
 
Vous devez vous inscrire ou vous connecter pour répondre ici.
Derniers messages publiés
Statistiques globales
Discussions
730 126
Messages
6 717 808
Membres
1 586 365
Dernier membre
matiOs1
Partager cette page
Haut