Construire un Robot Hexapode

14 décembre 2011
Robot Hexapode
Sommaire :
Voici une page décrivant la construction d'un robot hexapode (mécanique, électronique, et algorithme). Le robot hexapode décrit ci-dessous consiste en une structure fixe à laquelle est attachée six pattes, trois pattes parallèles à trois autres. Le robot a donc une forme de rectangle.

Chaque patte doit avoir deux degrés de liberté : elle doit pouvoir se soulever et avancer. On va donc utiliser deux servomoteurs par patte, car ceux-ci permettent de contrôler très facilement et avec précision la position de la patte. Ils permettent de faciliter l'assemblage étant donné que les engrenages de réduction sont présents dans le boitier du servomoteur.

Le robot sera construit avec de l'aluminium : celui-ci permet un usinage facile et une bonne solidité.


La 'marche' d'un hexapode

Il y a de nombreuse façon de faire marcher un hexapode, voici deux façons de faire.
Pour simplifier les explications, on va numéroter les pattes :
Numérotation des pattes de l'hexapode La partie touchant le sol sera la 'jambe' de l'hexapode, et la partie reliant le robot à sa jambe sera sa 'cuisse'.

La marche la plus simple à implémenter mais aussi la plus lente aussi consiste à soulever la patte 1 (la jambe), l'avancer (la cuisse) puis à la reposer (la jambe), et ainsi de suite pour toute les pattes. Puis on remet toutes les pattes (les 'cuisses') dans l'axe du robot, comme à l'état initial. Le robot a ainsi avancé de quelques centimètres.

Un autre type de marche, beaucoup plus efficace consiste à faire avancer l'hexapode 3 pattes par 3 pattes. En effet, seules 3 pattes sont nécessaires pour qu'il tienne debout. Ainsi 3 pattes avancent quand les 3 autres sont statiques.
Tout d'abord, on soulève les 'jambes' 1, 3 et 5 puis on avance les 3 'cuisses' de ces mêmes pattes, et on repose les jambes. Ensuite on soulève les autres jambes (2, 4 et 6) et on remet les cuisses 1, 3 et 5 dans leur état initial (perpendiculaire au sens de la marche). Le robot avance ainsi de quelques centimètres. On continue ensuite la même chose pour les trois autres pattes :
On avance les cuisses 2, 4 et 6; on repose les jambes 2, 4 et 6; on soulève les jambes 1, 3 et 5; on remet dans leur sens initial les cuisses 2, 4 et 6.
Le robot avance un peu, et on se retrouve dans la même configuration qu'au début. On continue donc cette 'boucle' pour avancer.

Pour faire avancer le robot vers la droite ou vers la gauche, il suffit d'avancer plus les pattes d'un côté que de l'autre.

La marche 3 par 3 en images :
La marche du robot 3 pattes par 3 pattes La marche du robot 3 pattes par 3 pattes La marche du robot 3 pattes par 3 pattes La marche du robot 3 pattes par 3 pattes La marche du robot 3 pattes par 3 pattes La marche du robot 3 pattes par 3 pattes La marche du robot 3 pattes par 3 pattes La marche du robot 3 pattes par 3 pattes


La mécanique

Robot Hexapode
Pour construire le robot hexapode, on va utiliser une lamelle d'aluminium de 2 ou 3 mm d'épaisseur.

Construction d'une « cuisse » de l'hexapode

On commence tout d'abord par faire les fixations pour les 6 servomoteurs des 'cuisses' du robot.
Voilà à quoi ressemble une 'cuisse' finie :
Une 'Cuisse' de l'hexapode

Pour la faire, il faut tout d'abord découper un bout d'aluminium de la largeur du servomoteur plus quelques millimètres.
Morceau d'aluminium qui va être fixé au servomoteur

Puis on perce des trous (pour les servomoteurs SG-5010, il faut percer des trous de diamètre 4mm) : quatre qui vont fixer la plaque au servomoteur, et deux qui vont fixer cette plaque à une autre plaque. Il faut ensuite faire une 'entaille' de la largeur du servomoteur juste à côté des trous de fixations du servomoteur.

On pointe les trous On pointe les trous On perce les trous
On perce les trous

On plie les deux extrémités, de façon à ce que l'on puisse glisser le servomoteur entre les deux pour le fixer (il suffit de serrer la plaque dans un étau et de taper légèrement sur l'extrémité avec un marteau).
Ainsi on peut faire une autre entaille et découper un petit bout de la plaque d'alu afin de pouvoir plier la plaque sur le haut du servomoteur sans gêner le mécanisme.
On plie la plaque On plie la plaque

Ensuite, on découpe une lamelle d'alu d'environ 1,5 fois la longueur du servo. On perce deux trous coincident avec les deux trous de la plaque d'alu précédente (sur le côté du servomoteur). Puis on visse le tout.
Découpe d'une nouvelle lamelle et perçage On 'Vis' la 'cuisse'

Il ne reste plus qu'à faire la fixation pour la 'jambe' du robot. Suivant le palonnier utilisé, les trous changent. Ici on perce deux petits trous pour fixer le palonnier à la plaque et un gros trou pour fixer le palonnier au servomoteur. J'ai agrandi légèrement les trous du palonnier pour pouvoir utiliser des vis de 3mm.

Perçage pour la fixation du palonnier Perçage pour la fixation du palonnier

Voilà ! La 'cuisse' de l'hexapode est finie, il faut maintenant faire sa 'jambe'.
Une 'Jambe' du robot

Construction d'une « jambe » de l'hexapode

La jambe est plus simple à fabriquer, elle consiste en une 'rallonge' pour le servomoteur afin d'y faire mettre un 'pied'. On coupe donc un bout de lamelle d'alu de quelques centimètres, et on diminue sa largeur pour quelle fasse la largeur du servomoteur. Ensuite on perce deux trous pour la fixer au servomoteur.
Pour avoir une plus grande surface d'appuie que le coin de la lamelle, on peut fabriquer un pied en plastique (cf Méthode pour transformer du plastique).


La structure du robot

La structure du robot consiste en un 'rectangle' d'aluminium où sont percés des trous pour la fixation des pattes.
Perçage pour la fixation du palonnier
On commence donc par découper une lamelle, qui sera un des deux côtés de la structure, dans laquelle on perce des trous pour la fixation des servomoteurs. La longueur de la lamelle à prendre est proportionnelle à la taille des servomoteurs, ici elle est d'environ 30cm.
Un des deux côtés de la structure Palonnier
Après avoir fait les deux côtés identiques, on fait les deux autres côtés : l'avant et l'arrière du robot. On procède de la même manière, on découpe une lamelle, et on perce dans chaque deux fixations pour les palonniers, mais cette fois ci dans l'autre sens, de façon à ce que ces fixations attachent aussi les quatre côtés de la structure ensemble. Pour donner l'ordre de grandeur, ici cette lamelle fait environ 14cm.

La structure du robot - Vue de dessous La structure du robot - Vue de dessus

Enfin, on peut rajouter une lamelle en diagonale afin de bien consolider la structure.

Il ne reste plus qu'à tout assembler : on visse la structure, et on attache tous les servomoteurs.
On peut alors utiliser une boite en plastique, que l'on attache sur le dessus, afin d'y mettre l'électronique qui va donner vie au robot.

Robot Hexapode


L'électronique

La partie électronique doit :
  • Commander les 12 servomoteurs du robot
  • Permettre l'envoi et la réception de donnée sans fil (pour commander le robot à distance)
  • Disposer de quelques entrées numériques et/ou analogiques de façon a pouvoir ajouter ultérieurement des capteurs / des nouvelles fonctionnalités
On va donc naturellement utiliser un microcontrôleur pour remplir ces fonctions.
La fonction 'sans fil' peut être effectuée par un module bluetooth/série, qui permet, pour un prix relativement faible, de communiquer avec un ordinateur ou avec un mobile (qui peut faire office de télécommande). Celui-ci est très simple à implémenter car il peut communiquer via une liaison série avec le microcontrôleur.
Schéma de l'électronique J'ai ici utilisé un MSP430G2452, auquel est adjoint deux MAX394 afin de démultiplexer les signaux de commandes des servomoteurs. Ainsi, seulement 7 pins du microcontrôleur sont utilisées, au lieu de 12.
Schéma du µC avec ses deux MAX394 Schéma du µC avec ses deux MAX394
Pour alimenter les servomoteurs, j'ai utilisé un régulateur à découpage, un LM2679, qui va transformer le 12V de la batterie en 6V sans trop de pertes.
Pour la liaison sans fil, un des nombreux modules uart-bluetooth d'eBay suffit pour une utilisation en intérieur, sans grande portée. Si vous voulez faire de votre téléphone une télécommande, cette page peu vous servir.


La programmation du microcontrôleur

Pour contrôler la position d'un servomoteur, il faut lui envoyer une impulsion de 1 à 2ms (1ms : gauche, 2ms : droite), toutes les 20ms. Après avoir envoyé les impulsions de commande, c'est à dire pendant les 18ms restants, on va lire les éventuelles données arrivées par bluetooth, puis on va régler la durée des prochaines impulsions de commande.
Les données reçues par bluetooth vont définir la vitesse, la direction du robot et le type de « marche » de robot. La durée des impulsions, qui correspondent à la position des servomoteurs, vont dépendre de l'étape où l'on est dans la marche de l'hexapode. Pour savoir quand faire le mouvement suivant, il faut avoir une approximation du temps qui passe. On va donc compter le nombre de fois où l'on envoie les impulsions de commande, car celles-ci sont envoyées toutes les 20ms. Algorithme
Voici une implémentation en C de cet algorithme. Le code est indépendant de toute architecture, il doit être adapté au microcontrôleur utilisé (il faut initialiser le microcontrôleur, et faire les fonctions pour l'UART et le changement d'état des pins).

int main( void )
{
	//... (Initialisation)
    
    // Variables contenant la position des servomoteurs
	signed char cuisse[6]={0}, jambe[6]={0};
    
    // Variables stockant le sens de rotation de chaque servomoteur
	const signed char cuisse_sens[6]={1, 1, -1, -1, -1, 1}, jambe_sens[6]={1, 1, -1, -1, -1, 1};
    
    // Données de calibration des servos, à ajuster experimentalement
	const signed char cuisse_calib[6]={10, 7, 15, 16, 16, 6}, jambe_calib[6]={0, 0, 24, 21, 23, 0};
    
	int k=0;// Compteur
    char step = 0;// Etape de la marche en cours
    char go = 0;// Type de marche
    char speed = 100;// Vitesse
    char dir = 0;// Direction
    unsigned char rx;// Donnée reçue
    
	while(1)
	{
        // On passe à l'étape suivante de la marche si assez de temps est passé, 
        // on modifie donc les variables cuisse et jambe, pour modifier la position des servos (ie la durée des impulsions)
		if(k>speed) {
			k=0;
            
            // Mode de marche 3 par 3
			if(go == MODE_TRI) {
				static char sb = 0;
				if(step > 2) {
					step=0;
					sb = (sb == 0) ? 1 : 0;
				}
				switch(step) {
					case 0:
						cuisse[sb] = cuisse[sb+2] = cuisse[sb+4] = DP;
                        cuisse[-sb+1] = cuisse[-sb+3] = cuisse[-sb+5] = 0;
						jambe[sb] = jambe[sb+2] = jambe[sb+4] = DG;
                        jambe[-sb+1] = jambe[-sb+3] = jambe[-sb+5] = 0;
						break;
					case 1:
						cuisse[sb] = cuisse[sb+2] = cuisse[sb+4] = DP;
                        cuisse[-sb+1] = cuisse[-sb+3] = cuisse[-sb+5] = 0;
						jambe[sb] = jambe[sb+2] = jambe[sb+4] = 0;
                        jambe[-sb+1] = jambe[-sb+3] = jambe[-sb+5] = 0;
						break;
					case 2:
						cuisse[sb] = cuisse[sb+2] = cuisse[sb+4] = DP;
                        cuisse[-sb+1] = cuisse[-sb+3] = cuisse[-sb+5] = 0;
						jambe[sb] = jambe[sb+2] = jambe[sb+4] = 0;
                        jambe[-sb+1] = jambe[-sb+3] = jambe[-sb+5] = DG;
						break;
				}
				if(dir == DIR_L) {cuisse[0] = cuisse[1] = cuisse[2] = jambe[0] = jambe[1] = jambe[2] = 0;}
				else if(dir == DIR_R) {cuisse[3] = cuisse[4] = cuisse[5] = jambe[3] = jambe[4] = jambe[5] = 0;}
			}
            // Mode de marche jambe par jambe
			else if(go == MODE_PPP) {
				if(step > 19)
					step=0;
				if(step == 0 || step == 19) {
					cuisse[0] = cuisse[1] = cuisse[2] = cuisse[3] = cuisse[4] = cuisse[5] = 0;
					jambe[0] = jambe[1] = jambe[2] = jambe[3] = jambe[4] = jambe[5] = 0;
				} else {
					char servo = (step-1)/3;
					if(servo == 1) servo = 5;
					else if(servo == 5) servo = 1;
					if((dir != DIR_L || servo >= 3) && (dir != DIR_R || servo < 3)) {
						switch((step-1)%3) {
							case 0:
								cuisse[servo] = 0;
								jambe[servo] = DG;
								break;
							case 1:
								cuisse[servo] = DP;
								jambe[servo] = DG;
								break;
							case 2:
								cuisse[servo] = DP;
								jambe[servo] = 0;
								break;
						}
					}
				}
			}
			step++;
		}
		k++;
		
        // Si l'uart a des données dans son buffer
		if(rxDataReady())
		{
    		// Lit le buffer de l'uart (fonction bloquante)
            rx = readRx();
            
    		if(rx == 'g' || rx == 'G')
    		{// Mode de 'marche'
				rx = readRx();
				step=0;
				if(rx == MODE_TRI+'0') {
					go = MODE_TRI;speed = 40;
                    
				} else if(rx == MODE_PPP+'0') {
					go = MODE_PPP;speed = 20;
                    
				} else {
					go = 0;
					cuisse[0] = cuisse[1] = cuisse[2] = cuisse[3] = cuisse[4] = cuisse[5] = 0;
					jambe[0] = jambe[1] = jambe[2] = jambe[3] = jambe[4] = jambe[5] = 0;
				}
    		}
    		else if(rx == 'd')
    		{// Direction
    			rx = readRx();
    			dir = rx;
    		}
    		else if(rx == 's')
    		{// Vitesse
    			rx = readRx();
    			rx -= '0';
    			if(rx >= 5 && rx <= 100)
    				speed = rx;
    		}
		}
		
        //Les servomoteurs utilisés supportent l'envoi d'impulsions toutes les 50/60ms
        
        // On sélectionne la sortie des servos 'cuisses' sur le MAX394
		setMAX394CommandHigh();
		// On envoie les impulsions de commande des servomoteurs 'cuisses'
		servosPulses(cuisse, cuisse_sens, cuisse_calib);
	    
    	wait10ms();
    	wait10ms();
    	wait10ms();
    	
        // On sélectionne la sortie des servos 'jambes' sur le MAX394
		setMAX394CommandLow();
		// On envoie les impulsions de commande des servomoteurs 'jambes'
		servosPulses(jambe, jambe_sens, jambe_calib);
	    
    	wait10ms();
    	wait10ms();
    	
	} // end while(1)
}

void servosPulses(signed char k[6], const signed char k_sens[6], const signed char k_calib[6]) {
	int i, j;
    // On met les sorties de commande des servomoteurs à l'état haut
	SetAllServosHigh();
	
	wait500us();
    // La boucle dure environ 1.6ms
	for(i=0;i<32;++i)
	{
		wait50us();
		for(j=0;j<6;++j) {
			if(k[j]*k_sens[j]+k_calib[j] == i) {
                // On met la commande du servomoteur à l'état bas, si l'impulsion a durée assez longtemps.
    			setServoLow(j);
    		}
    	}
	}
    // On vérifie que toutes les sorties de commande sont à l'état bas
	SetAllServosLow();	
}


Catégories