Aller au menu - Aller au contenu

Icône Accéléromètre

Mise à jour : 01/02/2012
Difficulté : Facile Facile Creative Commons BY-NC-SA
19 893 visites depuis 7 jours, dont 126 sur ce chapitre classé 18/786
Les iPhone, iPod Touch et iPad sont équipés d'un accéléromètre qui leur permet de déterminer leur orientation par rapport au sol. Dans ce chapitre, je vais vous montrer comment utiliser les données renvoyées par l'accéléromètre pour afficher l'inclinaison du device et détecter s'il a été agité.

Cela vous tente ? Allons-y de ce pas !
Sommaire du chapitre :
Icône du chapitre
Chapitre précédent Sommaire Chapitre suivant

Mise en place de l'application

Avant de commencer



Les accélérations détectées par l'accéléromètre consistent en trois valeurs flottantes qui représentent les trois axes du device, comme indiqué à la figure suivante.

Les trois axes du device


Pour obtenir ces informations, vous utiliserez la classe UIAccelerometer. Un coup d'œil à l'aide Apple montre que les événements générés par les objets de cette classe se font via le protocole UIAccelerometerDelegate. Un autre coup d'œil à l'aide Apple sur le protocole UIAccelerometerDelegate montre que la méthode événementielle à utiliser pour recevoir les données relatives à l'accélération est didAccelerate.

Il ne reste plus qu'à implémenter un objet de la classe UIAccelerometer et à gérer les événements renvoyés par cet objet dans la méthode didAccelerate pour connaître la position du device.

Définition de l'interface de l'application



Définissez un nouveau projet de type Single View Application et donnez-lui le nom « accelerometre ».

Une fois le projet créé, cliquez sur MainStoryboard.storyboard dans le volet de navigation. Ajoutez un contrôle Label à la vue de l'application. Double-cliquez dessus et tapez « Accéléromètre » au clavier. Choisissez une police à votre convenance et un corps élevé pour que ce Label fasse office de titre (pour l'exemple, j'ai choisi une police Helvetica de corps 43).

Pour modifier la police et le corps du Label, cliquez sur le Label dans le canevas (1), affichez l'inspecteur des attributs en cliquant sur l'icône Show the Attributes inspector dans le volet des utilitaires (2), puis agissez sur le paramètre Font (3), comme indiqué à la figure suivante


Vous pouvez modifier la police et le corps du Label


Insérez quatre autres Label dans la partie inférieure de la vue. Déplacez-les et alignez-les pour obtenir quelque chose ressemblant à la figure suivante.

Ajoutez des Label et disposez-les de la sorte


Liaison des contrôles au code



Pour que l'application puisse afficher des informations dans les quatre derniers Label, vous devez établir un lien entre l'interface et le code.

Affichez côte à côte la zone d'édition et le fichier ViewController.h en cliquant sur l'icône Show the Assistant editor dans la barre d'outils.

Contrôle-glissez-déposez tour à tour les quatre derniers Label et définissez les outlets x, y, z et mouvement. Le fichier ViewController.h doit maintenant ressembler à ceci :

Code : Objective-C
1
2
3
4
5
6
7
8
9
#import <UIKit/UIKit.h>

@interface ViewController : UIViewController
@property (weak, nonatomic) IBOutlet UILabel *x;
@property (weak, nonatomic) IBOutlet UILabel *y;
@property (weak, nonatomic) IBOutlet UILabel *z;
@property (weak, nonatomic) IBOutlet UILabel *mouvement;

@end

Écriture du code

L'interface et le fichier d'en-têtes étant définis, il ne reste plus qu'à écrire un peu de code pour faire fonctionner tout ce petit monde. Cliquez sur ViewController.m dans le volet de navigation.

Dans un premier temps, vous allez ajouter un arrière-plan à l'application. Définissez un dossier Resources dans l'arborescence de l'application, procurez-vous une image de 320x480 pixels et ajoutez-la à ce dossier.

Pour que l'image d'arrière-plan s'affiche dès l'ouverture de l'application, ajoutez l'instruction suivante dans la méthode viewDidLoad (cette instruction suppose que l'image d'arrière-plan a pour nom « gyro.jpg ») :

Code : Objective-C
1
self.view.backgroundColor = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:@"gyro.jpg"]];


Vous allez maintenant définir un objet de classe UIAccelerometer et l'initialiser. Complétez la méthode viewDidLoad comme suit :

Code : Objective-C
1
2
3
4
5
6
7
8
9
- (void)viewDidLoad
{
  [super viewDidLoad];
  self.view.backgroundColor = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:@"gyro.jpg"]];
  UIAccelerometer *testAccel = [UIAccelerometer sharedAccelerometer];
  testAccel.delegate = self;
  testAccel.updateInterval = 0.1f;
  [mouvement setText:@"Le device est calme"];
}


À la ligne 5, nous définissons l'objet testAccel de type UIAccelerator. Cet objet est initialisé avec la méthode sharedAccelerometer, comme indiqué dans la documentation Apple :

Code : Objective-C
1
UIAccelerometer *testAccel = [UIAccelerometer sharedAccelerometer];


La ligne 6 indique que les événements relatifs à l'objet testAccel seront traités dans la classe courante, c'est-à-dire dans la classe de la vue :

Code : Objective-C
1
testAccel.delegate = self;


À la ligne 7, nous utilisons la propriété updateInterval pour définir la période de la mise à jour des données fournies par l'accéléromètre. Ici, tous les 1/10 seconde :

Code : Objective-C
1
testAccel.updateInterval = 0.1f;


Enfin, la ligne 8 affiche le message « Le device est calme » dans le Label mouvement pour indiquer que le device n'est pas agité :

Code : Objective-C
1
[mouvement setText:@"Le device est calme"];


Si je me souviens de ce qui a été dit au début de cette section, il est nécessaire d'implémenter le protocole UIAccelerometerDelegate. Est-ce qu'il ne faudrait pas agir sur le fichier d'en-têtes pour cela ?


Tout à fait exact. D'ailleurs, le message d'avertissement affiché en face de la ligne testAccel.delegate = self; (figure suivante) le confirme :

Un message d'erreur apparaît


Cliquez sur ViewController.h dans le volet de navigation et ajoutez la référence au delegate dans l'instruction @interface :

Code : Objective-C
1
2
3
4
@interface accelerometreViewController : UIViewController <UIAccelerometerDelegate> 
{
  ...
}


En consultant la documentation Apple relative à UIAccelerometerDelegate, vous verrez que la méthode didAccelerate est appelée lorsque de nouvelles données issues de l'accéléromètre sont disponibles. Définissez cette méthode comme suit :

Code : Objective-C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration 
{
  if (fabsf(acceleration.x) > 1.5 || fabsf(acceleration.y) > 1.5 || fabsf(acceleration.z) > 1.5)
  {    
    [mouvement setText:@"J'ai détecté une secousse"];
    if (temporisation == 0)
      temporisation = 1;
  }   

  x.text=[NSString stringWithFormat:@"%@ %f",@"X =",acceleration.x];
  y.text=[NSString stringWithFormat:@"%@ %f",@"Y =",acceleration.y];
  z.text=[NSString stringWithFormat:@"%@ %f",@"Z =",acceleration.z];

  if (temporisation > 0)
    temporisation++;
  if (temporisation == 30)
  {    
    [mouvement setText:@"Le device est calme"];
    temporisation = 0;
  }    
}


N'ayez crainte, il n'y a rien de bien méchant dans cette méthode !

Si le gabarit de la méthode vous semble compliqué, sachez qu'il a été automatiquement proposé par Xcode dès la saisie du mot accelerometer, comme le montre la figure suivante.

Xcode vous propose automatiquement le gabarit de la méthode


Les accélérations selon les axes X, Y et Z sont accessibles dans les propriétés x, y et z de l'objet acceleration. L'instruction de la ligne 3 teste si l'accélération du device est supérieure à 1,5 selon un des axes :

Code : Objective-C
1
if (fabsf(acceleration.x) > 1.5 || fabsf(acceleration.y) > 1.5 || fabsf(acceleration.z) > 1.5)


Dans ce cas, le device a été agité, et un texte est affiché en conséquence dans le Label mouvement :

Code : Objective-C
1
[mouvement setText:@"J'ai détecté une secousse"];


Remarquez l'utilisation de la fonction fabsf() qui renvoie la valeur absolue de son argument. En d'autres termes, l'argument privé de son signe. L'accélération peut en effet être négative. En la privant de son signe, il est plus facile de tester si elle dépasse une certaine limite et ainsi décréter qu'il y a eu une agitation du device.


Rappelez-vous : la mise à jour des quatre Labels se fait 10 fois par seconde. Il est donc nécessaire de mettre en place un artifice pour que le texte « J'ai détecté une secousse » reste affiché plus longtemps, sans quoi il sera pratiquement impossible de le voir. C'est le rôle des deux instructions qui suivent :

Code : Objective-C
1
2
if (temporisation == 0)
  temporisation = 1;


La variable temporisation vaut 0 par défaut. Elle indique que le device n'a pas été agité. Elle est mise à 1 pour indiquer que le device vient d'être agité.

Les lignes 10 à 12 affichent les valeurs des accélérations dans les labels x, y et z :

Code : Objective-C
1
2
3
x.text=[NSString stringWithFormat:@"%@ %f",@"X =",acceleration.x];
y.text=[NSString stringWithFormat:@"%@ %f",@"Y =",acceleration.y];
z.text=[NSString stringWithFormat:@"%@ %f",@"Z =",acceleration.z];


Il n'y a pas grand-chose à dire au sujet de ces instructions. D'une façon très classique, la méthode stringWithFormat est utilisée pour concaténer deux éléments (ici, un texte et un flottant) et les convertir en un NSString.

Le bloc d'instructions suivant est plus intéressant. C'est lui qui se charge d'afficher le texte « J'ai détecté une secousse » pendant trois secondes.
Si la variable temporisation est supérieure à 0, on l'incrémente :

Code : Objective-C
1
2
if (temporisation > 0)
  temporisation++;


Si elle a pour valeur 30, ou en d'autres termes, si elle est passée une trentaine de fois par ce code (28 exactement), cela signifie qu'environ 3 secondes se sont écoulées depuis l'affichage du texte « J'ai détecté une secousse » dans le Label :

Code : Objective-C
1
if (temporisation == 30)


Dans ce cas, le texte « Le device est calme » est affiché dans ce même Label et la variable temporisation est mise à 0, en attendant que le device soit agité une nouvelle fois :

Code : Objective-C
1
2
3
4
{ 
  [mouvement setText:@"Le device est calme"];
  temporisation = 0;
}


Pour que ce code fonctionne, deux petites lignes doivent être ajoutées.

La variable temporisation doit être initialisée à 0 dans la méthode viewDidLoad :

Code : Objective-C
1
2
3
4
5
6
- (void)viewDidLoad
{
  ...
  temporisation = 0;
  ...
}


La variable temporisation doit être déclarée dans le fichier d'en-têtes :

Code : Objective-C
1
2
3
4
5
@interface accelerometreViewController : UIViewController <UIAccelerometerDelegate> 
{
  ...
  int temporisation;
}


Ça y est, l'application est entièrement fonctionnelle. Vous pouvez la lancer (pas dans le simulateur, évidemment !). La figure suivante représente ce que j'ai obtenu.

Mon application est terminée et fonctionnelle


Cette application se trouve dans le dossier accelerometre.


ViewController.h


Secret (cliquez pour afficher)

Code : Objective-C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#import <UIKit/UIKit.h>

@interface ViewController : UIViewController <UIAccelerometerDelegate> 
{
  int temporisation;
}

@property (weak, nonatomic) IBOutlet UILabel *x;
@property (weak, nonatomic) IBOutlet UILabel *y;
@property (weak, nonatomic) IBOutlet UILabel *z;
@property (weak, nonatomic) IBOutlet UILabel *mouvement;

@end



ViewController.m


Secret (cliquez pour afficher)

Code : Objective-C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#import "ViewController.h"

@implementation ViewController
@synthesize x;
@synthesize y;
@synthesize z;
@synthesize mouvement;

- (void)didReceiveMemoryWarning
{
  [super didReceiveMemoryWarning];
  // Release any cached data, images, etc that aren't in use.
}

#pragma mark - View lifecycle

- (void)viewDidLoad
{
  [super viewDidLoad];
  self.view.backgroundColor = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:@"gyro.jpg"]];
  UIAccelerometer *testAccel = [UIAccelerometer sharedAccelerometer];
  testAccel.delegate = self;
  testAccel.updateInterval = 0.1f;
  temporisation = 0;
  [mouvement setText:@"Le device est calme"];
}

- (void)viewDidUnload
{
  [self setX:nil];
  [self setY:nil];
  [self setZ:nil];
  [self setMouvement:nil];
  [super viewDidUnload];
  // Release any retained subviews of the main view.
  // e.g. self.myOutlet = nil;
}

- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration 
{
  if (fabsf(acceleration.x) > 1.5 || fabsf(acceleration.y) > 1.5 || fabsf(acceleration.z) > 1.5)
  { 
    [mouvement setText:@"J'ai détecté une secousse"];
    if (temporisation == 0)
      temporisation = 1;
  }

  x.text=[NSString stringWithFormat:@"%@ %f",@"X =",acceleration.x];
  y.text=[NSString stringWithFormat:@"%@ %f",@"Y =",acceleration.y];
  z.text=[NSString stringWithFormat:@"%@ %f",@"Z =",acceleration.z];

  if (temporisation > 0)
    temporisation++;
  if (temporisation == 30)
  { 
    [mouvement setText:@"Le device est calme"];
    temporisation = 0;
  } 
}

- (void)viewWillAppear:(BOOL)animated
{
  [super viewWillAppear:animated];
}

- (void)viewDidAppear:(BOOL)animated
{
  [super viewDidAppear:animated];
}

- (void)viewWillDisappear:(BOOL)animated
{
  [super viewWillDisappear:animated];
}

- (void)viewDidDisappear:(BOOL)animated
{
  [super viewDidDisappear:animated];
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
  // Return YES for supported orientations
  return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}

@end

Q.C.M.

Quelle classe doit-on utiliser pour obtenir les informations issues de l'accéléromètre embarqué dans les iPhone/iPod Touch et iPad ?
Dans quelle méthode est-il courant de déclarer l'objet UIAccelerometer ?
Quel protocole est-il nécessaire d'implémenter pour gérer les événements issus de l'accéléromètre ?

Statistiques de réponses au QCM

En résumé


  • Les accélérations détectées par l'accéléromètre consistent en trois valeurs flottantes qui représentent les trois axes du device. Pour obtenir ces informations, vous utiliserez la classe UIAccelerometer.
  • Définissez un objet de classe UIAccelerometer, définissez la période de mise à jour des informations le concernant avec la propriété updateInterval et utilisez la méthode didAccelerate pour obtenir les valeurs instantanées de l'accélération (acceleration.x, acceleration.y et acceleration.z).
  • Pour détecter une secousse sur le device, il suffit que l'une des composantes d'accélération renvoyées par l'objet acceleration soit supérieure à une valeur donnée (1,5 par exemple).
Chapitre précédent Sommaire Chapitre suivant

Partager

Il n'y a pas encore de commentaire pour ce tuto.