Code pour le projet de robot autonome : Partie 1
Afin de vous simplifier le travail dans le cadre du projet robot, les éléments de code de taille importante à insérer au fur et à mesure du projet sont regroupés sur cette page. A noter qu’en cas d’incohérence avec le sujet, c’est celui-ci qui fait est juste a priori. Si c’est le cas, merci de me le signaler.
Pour formater proprement vos fichiers dans MPLABX, vous pouvez utiliser le raccourci de formatage automatique ALT+MAJ+F, après avoir au préalable sélectionné le texte à formater.
Main initial
#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
#include « ChipConfig.h »
#include « IO.h »
int main (void){
/***************************************************************************************************/
//Initialisation de l’oscillateur
/****************************************************************************************************/
InitOscillator();
/****************************************************************************************************/
// Configuration des entrées sorties
/****************************************************************************************************/
InitIO();
LED_BLANCHE = 1;
LED_BLEUE = 1;
LED_ORANGE = 1;
/****************************************************************************************************/
// Boucle Principale
/****************************************************************************************************/
while(1){
} // fin main
}
Partie Timer
#include <xc.h>
#include « timer.h »
#include « IO.h »
//Initialisation d’un timer 32 bits
void InitTimer23(void) {
T3CONbits.TON = 0; // Stop any 16-bit Timer3 operation
T2CONbits.TON = 0; // Stop any 16/32-bit Timer3 operation
T2CONbits.T32 = 1; // Enable 32-bit Timer mode
T2CONbits.TCS = 0; // Select internal instruction cycle clock
T2CONbits.TCKPS = 0b00; // Select 1:1 Prescaler
TMR3 = 0x00; // Clear 32-bit Timer (msw)
TMR2 = 0x00; // Clear 32-bit Timer (lsw)
PR3 = 0x0262; // Load 32-bit period value (msw)
PR2 = 0x5A00; // Load 32-bit period value (lsw)
IPC2bits.T3IP = 0x01; // Set Timer3 Interrupt Priority Level
IFS0bits.T3IF = 0; // Clear Timer3 Interrupt Flag
IEC0bits.T3IE = 1; // Enable Timer3 interrupt
T2CONbits.TON = 1; // Start 32-bit Timer
/* Example code for Timer3 ISR */
}
//Interruption du timer 32 bits sur 2-3
void __attribute__((interrupt, no_auto_psv)) _T3Interrupt(void) {
IFS0bits.T3IF = 0; // Clear Timer3 Interrupt Flag
LED_ORANGE = !LED_ORANGE;
}
//Initialisation d’un timer 16 bits
void InitTimer1(void)
{
//Timer1 pour horodater les mesures (1ms)
T1CONbits.TON = 0; // Disable Timer
T1CONbits.TCKPS = 0b01; //Prescaler
//11 = 1:256 prescale value
//10 = 1:64 prescale value
//01 = 1:8 prescale value
//00 = 1:1 prescale value
T1CONbits.TCS = 0; //clock source = internal clock
PR1 = 0x1388;
IFS0bits.T1IF = 0; // Clear Timer Interrupt Flag
IEC0bits.T1IE = 1; // Enable Timer interrupt
T1CONbits.TON = 1; // Enable Timer
}
//Interruption du timer 1
void __attribute__((interrupt, no_auto_psv)) _T1Interrupt(void)
{
IFS0bits.T1IF = 0;
LED_BLANCHE = !LED_BLANCHE;
}
Robot.h
#ifndef ROBOT_H
#define ROBOT_H
typedef struct robotStateBITS {
union {
struct {
unsigned char taskEnCours;
float vitesseGaucheConsigne;
float vitesseGaucheCommandeCourante;
float vitesseDroiteConsigne;
float vitesseDroiteCommandeCourante;}
;}
;} ROBOT_STATE_BITS;
extern volatile ROBOT_STATE_BITS robotState;
#endif /* ROBOT_H */
ToolBox
#include « Toolbox.h »
float Abs(float value)
{
if (value >= 0)
return value;
else return -value;
}
float Max(float value, float value2)
{
if (value > value2)
return value;
else
return value2;
}
float Min(float value, float value2)
{
if (value < value2)
return value;
else
return value2;
}
float LimitToInterval(float value, float lowLimit, float highLimit)
{
if (value > highLimit)
value = highLimit;
else if (value < lowLimit)
value = lowLimit;
return value;
}
float RadianToDegree(float value)
{
return value / PI * 180.0;
}
float DegreeToRadian(float value)
{
return value * PI / 180.0;
}
Partie PWM
//Partie PWM
#include <xc.h> // library xc.h inclut tous les uC
#include « IO.h »
#include « PWM.h »
#include « Robot.h »
#include « ToolBox.h »
#define PWMPER 40.0
unsigned char acceleration = 20;
void InitPWM(void)
{
PTCON2bits.PCLKDIV = 0b000; //Divide by 1
PTPER = 100*PWMPER; //Période en pourcentage
//Réglage PWM moteur 1 sur hacheur 1
IOCON1bits.POLH = 1; //High = 1 and active on low =0
IOCON1bits.POLL = 1; //High = 1
IOCON1bits.PMOD = 0b01; //Set PWM Mode to Redundant
FCLCON1 = 0x0003; //Désactive la gestion des faults
//Reglage PWM moteur 2 sur hacheur 6
IOCON6bits.POLH = 1; //High = 1
IOCON6bits.POLL = 1; //High = 1
IOCON6bits.PMOD = 0b01; //Set PWM Mode to Redundant
FCLCON6 = 0x0003; //Désactive la gestion des faults
/* Enable PWM Module */
PTCONbits.PTEN = 1;
}
void PWMSetSpeed(float vitesseEnPourcents)
{
robotState.vitesseGaucheCommandeCourante = vitesseEnPourcents;
MOTEUR_GAUCHE_L_PWM_ENABLE = 0; //Pilotage de la pin en mode IO
MOTEUR_GAUCHE_L_IO_OUTPUT = 1; //Mise à 1 de la pin
MOTEUR_GAUCHE_H_PWM_ENABLE = 1; //Pilotage de la pin en mode PWM
MOTEUR_GAUCHE_DUTY_CYCLE = Abs(robotState.vitesseGaucheCommandeCourante*PWMPER);
}
Definition des pins Hacheurs
//Définitions des pins pour les hacheurs moteurs
#define MOTEUR1_IN1 _LATB14
#define MOTEUR1_IN2 _LATB15
//Configuration spécifique du moteur gauche
#define MOTEUR_GAUCHE_H_IO_OUTPUT MOTEUR1_IN1
#define MOTEUR_GAUCHE_L_IO_OUTPUT MOTEUR1_IN2
#define MOTEUR_GAUCHE_L_PWM_ENABLE IOCON1bits.PENL
#define MOTEUR_GAUCHE_H_PWM_ENABLE IOCON1bits.PENH
#define MOTEUR_GAUCHE_DUTY_CYCLE PDC1
Rampes de vitesse
void PWMUpdateSpeed()
{
// Cette fonction est appelée sur timer et permet de suivre des rampes d’accélération
if (robotState.vitesseDroiteCommandeCourante < robotState.vitesseDroiteConsigne)
robotState.vitesseDroiteCommandeCourante = Min(
robotState.vitesseDroiteCommandeCourante + acceleration,
robotState.vitesseDroiteConsigne);
if (robotState.vitesseDroiteCommandeCourante > robotState.vitesseDroiteConsigne)
robotState.vitesseDroiteCommandeCourante = Max(
robotState.vitesseDroiteCommandeCourante – acceleration,
robotState.vitesseDroiteConsigne);
if (robotState.vitesseDroiteCommandeCourante > 0)
{
MOTEUR_DROIT_L_PWM_ENABLE = 0; //pilotage de la pin en mode IO
MOTEUR_DROIT_L_IO_OUTPUT = 1; //Mise à 1 de la pin
MOTEUR_DROIT_PWM_ENABLE_H = 1; //Pilotage de la pin en mode PWM
}
else
{
MOTEUR_DROIT_H_PWM_ENABLE = 0; //pilotage de la pin en mode IO
MOTEUR_DROIT_H_IO_OUTPUT = 1; //Mise à 1 de la pin
MOTEUR_DROIT_L_PWM_ENABLE = 1; //Pilotage de la pin en mode PWM
}
MOTEUR_DROIT_DUTY_CYCLE = Abs(robotState.vitesseDroiteCommandeCourante)*PWMPER;
if (robotState.vitesseGaucheCommandeCourante < robotState.vitesseGaucheConsigne)
robotState.vitesseGaucheCommandeCourante = Min(
robotState.vitesseGaucheCommandeCourante + acceleration,
robotState.vitesseGaucheConsigne);
if (robotState.vitesseGaucheCommandeCourante > robotState.vitesseGaucheConsigne)
robotState.vitesseGaucheCommandeCourante = Max(
robotState.vitesseGaucheCommandeCourante – acceleration,
robotState.vitesseGaucheConsigne);
if (robotState.vitesseGaucheCommandeCourante > 0)
{
MOTEUR_GAUCHE_L_PWM_ENABLE = 0; //pilotage de la pin en mode IO
MOTEUR_GAUCHE_L_IO_OUTPUT = 1; //Mise à 1 de la pin
MOTEUR_GAUCHE_H_PWM_ENABLE = 1; //Pilotage de la pin en mode PWM
}
else
{
MOTEUR_GAUCHE_H_PWM_ENABLE = 0; //pilotage de la pin en mode IO
MOTEUR_GAUCHE_H_IO_OUTPUT = 1; //Mise à 1 de la pin
MOTEUR_GAUCHE_L_PWM_ENABLE = 1; //Pilotage de la pin en mode PWM
}
MOTEUR_GAUCHE_DUTY_CYCLE = Abs(robotState.vitesseGaucheCommandeCourante) * PWMPER;
}
Conversions analogiques numériques
#include <xc.h>
#include « adc.h »
#include « main.h »
unsigned char ADCResultIndex = 0;
static unsigned int ADCResult[4];
unsigned char ADCConversionFinishedFlag;
/****************************************************************************************************/
// Configuration ADC
/****************************************************************************************************/
void InitADC1(void)
{
//cf. ADC Reference Manual page 47
//Configuration en mode 12 bits mono canal ADC avec conversions successives sur 4 entrées
/************************************************************/
//AD1CON1
/************************************************************/
AD1CON1bits.ADON = 0; // ADC module OFF – pendant la config
AD1CON1bits.AD12B = 1; // 0 : 10bits – 1 : 12bits
AD1CON1bits.FORM = 0b00; // 00 = Integer (DOUT = 0000 dddd dddd dddd)
AD1CON1bits.ASAM = 0; // 0 = Sampling begins when SAMP bit is set
AD1CON1bits.SSRC = 0b111; // 111 = Internal counter ends sampling and starts conversion (auto-convert)
/************************************************************/
//AD1CON2
/************************************************************/
AD1CON2bits.VCFG = 0b000; // 000 : Voltage Reference = AVDD AVss
AD1CON2bits.CSCNA = 1; // 1 : Enable Channel Scanning
AD1CON2bits.CHPS = 0b00; // Converts CH0 only
AD1CON2bits.SMPI = 2; // 2+1 conversions successives avant interrupt
AD1CON2bits.ALTS = 0;
AD1CON2bits.BUFM = 0;
/************************************************************/
//AD1CON3
/************************************************************/
AD1CON3bits.ADRC = 0; // ADC Clock is derived from Systems Clock
AD1CON3bits.ADCS = 15; // ADC Conversion Clock TAD = TCY * (ADCS + 1)
AD1CON3bits.SAMC = 15; // Auto Sample Time
/************************************************************/
//AD1CON4
/************************************************************/
AD1CON4bits.ADDMAEN = 0; // DMA is not used
/************************************************************/
//Configuration des ports
/************************************************************/
//ADC utilisés : 16(G9)-11(C11)-6(C0)
ANSELCbits.ANSC0 = 1;
ANSELCbits.ANSC11 = 1;
ANSELGbits.ANSG9 = 1;
AD1CSSLbits.CSS6=1; // Enable AN6 for scan
AD1CSSLbits.CSS11=1; // Enable AN11 for scan
AD1CSSHbits.CSS16=1; // Enable AN16 for scan
/* Assign MUXA inputs */
AD1CHS0bits.CH0SA = 0;// CH0SA bits ignored for CH0 +ve input selection
AD1CHS0bits.CH0NA = 0;// Select VREF- for CH0 -ve inpu
IFS0bits.AD1IF = 0; // Clear the A/D interrupt flag bit
IEC0bits.AD1IE = 1; // Enable A/D interrupt
AD1CON1bits.ADON = 1; // Turn on the A/D converter
}
/* This is ADC interrupt routine */
void __attribute__((interrupt, no_auto_psv)) _AD1Interrupt(void)
{
IFS0bits.AD1IF = 0;
ADCResult[0] = ADC1BUF0;// Read the AN-scan input 1 conversion result
ADCResult[1] = ADC1BUF1;// Read the AN3 conversion result
ADCResult[2] = ADC1BUF2;// Read the AN5 conversion result
ADCConversionFinishedFlag = 1;
}
void ADC1StartConversionSequence()
{
AD1CON1bits.SAMP = 1 ; //Lance une acquisition ADC
}
unsigned int * ADCGetResult(void)
{
return ADCResult;
}
unsigned char ADCIsConversionFinished(void)
{
return ADCConversionFinishedFlag;
}
void ADCClearConversionFinishedFlag(void)
{
ADCConversionFinishedFlag = 0;
}
Réglage automatique des timers
void SetFreqTimer1(float freq)
{
T1CONbits.TCKPS = 0b00; //00 = 1:1 prescaler value
if(FCY /freq > 65535)
{
T1CONbits.TCKPS = 0b01; //01 = 1:8 prescaler value
if(FCY /freq / 8 > 65535)
{
T1CONbits.TCKPS = 0b10; //10 = 1:64 prescaler value
if(FCY /freq / 64 > 65535)
{
T1CONbits.TCKPS = 0b11; //11 = 1:256 prescaler value
PR1 = (int)(FCY / freq / 256);
}
else
PR1 = (int)(FCY / freq / 64);
}
else
PR1 = (int)(FCY / freq / 8);
}
else
PR1 = (int)(FCY / freq);
}
Définition des états de la machine à état de gestion du robot
#define STATE_ATTENTE 0
#define STATE_ATTENTE_EN_COURS 1
#define STATE_AVANCE 2
#define STATE_AVANCE_EN_COURS 3
#define STATE_TOURNE_GAUCHE 4
#define STATE_TOURNE_GAUCHE_EN_COURS 5
#define STATE_TOURNE_DROITE 6
#define STATE_TOURNE_DROITE_EN_COURS 7
#define STATE_TOURNE_SUR_PLACE_GAUCHE 8
#define STATE_TOURNE_SUR_PLACE_GAUCHE_EN_COURS 9
#define STATE_TOURNE_SUR_PLACE_DROITE 10
#define STATE_TOURNE_SUR_PLACE_DROITE_EN_COURS 11
#define STATE_ARRET 12
#define STATE_ARRET_EN_COURS 13
#define STATE_RECULE 14
#define STATE_RECULE_EN_COURS 15
#define PAS_D_OBSTACLE 0
#define OBSTACLE_A_GAUCHE 1
#define OBSTACLE_A_DROITE 2
#define OBSTACLE_EN_FACE 3
Machine à état de gestion du robot
unsigned char stateRobot;
void OperatingSystemLoop(void)
{
switch (stateRobot)
{
case STATE_ATTENTE:
timestamp = 0;
PWMSetSpeedConsigne(0, MOTEUR_DROIT);
PWMSetSpeedConsigne(0, MOTEUR_GAUCHE);
stateRobot = STATE_ATTENTE_EN_COURS;
case STATE_ATTENTE_EN_COURS:
if (timestamp > 1000)
stateRobot = STATE_AVANCE;
break;
case STATE_AVANCE:
PWMSetSpeedConsigne(30, MOTEUR_DROIT);
PWMSetSpeedConsigne(30, MOTEUR_GAUCHE);
stateRobot = STATE_AVANCE_EN_COURS;
break;
case STATE_AVANCE_EN_COURS:
SetNextRobotStateInAutomaticMode();
break;
case STATE_TOURNE_GAUCHE:
PWMSetSpeedConsigne(30, MOTEUR_DROIT);
PWMSetSpeedConsigne(0, MOTEUR_GAUCHE);
stateRobot = STATE_TOURNE_GAUCHE_EN_COURS;
break;
case STATE_TOURNE_GAUCHE_EN_COURS:
SetNextRobotStateInAutomaticMode();
break;
case STATE_TOURNE_DROITE:
PWMSetSpeedConsigne(0, MOTEUR_DROIT);
PWMSetSpeedConsigne(30, MOTEUR_GAUCHE);
stateRobot = STATE_TOURNE_DROITE_EN_COURS;
break;
case STATE_TOURNE_DROITE_EN_COURS:
SetNextRobotStateInAutomaticMode();
break;
case STATE_TOURNE_SUR_PLACE_GAUCHE:
PWMSetSpeedConsigne(15, MOTEUR_DROIT);
PWMSetSpeedConsigne(-15, MOTEUR_GAUCHE);
stateRobot = STATE_TOURNE_SUR_PLACE_GAUCHE_EN_COURS;
break;
case STATE_TOURNE_SUR_PLACE_GAUCHE_EN_COURS:
SetNextRobotStateInAutomaticMode();
break;
case STATE_TOURNE_SUR_PLACE_DROITE:
PWMSetSpeedConsigne(-15, MOTEUR_DROIT);
PWMSetSpeedConsigne(15, MOTEUR_GAUCHE);
stateRobot = STATE_TOURNE_SUR_PLACE_DROITE_EN_COURS;
break;
case STATE_TOURNE_SUR_PLACE_DROITE_EN_COURS:
SetNextRobotStateInAutomaticMode();
break;
default :
stateRobot = STATE_ATTENTE;
break;
}
}
unsigned char nextStateRobot=0;
void SetNextRobotStateInAutomaticMode()
{
unsigned char positionObstacle = PAS_D_OBSTACLE;
//Détermination de la position des obstacles en fonction des télémètres
if ( robotState.distanceTelemetreDroit < 30 &&
robotState.distanceTelemetreCentre > 20 &&
robotState.distanceTelemetreGauche > 30) //Obstacle à droite
positionObstacle = OBSTACLE_A_DROITE;
else if(robotState.distanceTelemetreDroit > 30 &&
robotState.distanceTelemetreCentre > 20 &&
robotState.distanceTelemetreGauche < 30) //Obstacle à gauche
positionObstacle = OBSTACLE_A_GAUCHE;
else if(robotState.distanceTelemetreCentre < 20) //Obstacle en face
positionObstacle = OBSTACLE_EN_FACE;
else if(robotState.distanceTelemetreDroit > 30 &&
robotState.distanceTelemetreCentre > 20 &&
robotState.distanceTelemetreGauche > 30) //pas d’obstacle
positionObstacle = PAS_D_OBSTACLE;
//Détermination de l’état à venir du robot
if (positionObstacle == PAS_D_OBSTACLE)
nextStateRobot = STATE_AVANCE;
else if (positionObstacle == OBSTACLE_A_DROITE)
nextStateRobot = STATE_TOURNE_GAUCHE;
else if (positionObstacle == OBSTACLE_A_GAUCHE)
nextStateRobot = STATE_TOURNE_DROITE;
else if (positionObstacle == OBSTACLE_EN_FACE)
nextStateRobot = STATE_TOURNE_SUR_PLACE_GAUCHE;
//Si l’on n’est pas dans la transition de l’étape en cours
if (nextStateRobot != stateRobot – 1)
stateRobot = nextStateRobot;
}