niveau — Trace un trait horizontal

Ceci est un bon exemple de programme qui nécessite beaucoup de travail de réflexion avec un papier et un crayon pour aboutir à un programme simple qui tient en quelques lignes.

Le tracé de la droite horizontale se fait avec les étapes suivantes.

  1. Remarque préliminaire : Les mathématiques faites ici manquent beaucoup de rigueur. Il y a des erreurs de signe plus ou moins volontaires ; les angles sont parfois pris par rapport à l’horizontale, parfois par rapport à la verticale ; etc. Si je construisais un avion (avec des vies en jeux), je referais proprement ces calculs ; c’est seulement une carte micro:bit, et ça à l’air de fonctionner, donc c’est bien comme ça.

  2. La carte fournit l’accélération selon les axes x, y et z, qu’il faut convertir en angles. Si la carte n’est pivotée uniquement selon l’axe x, la gravité est proportionnelle au cosinus de l’angle (où 0 est l’horizontale). Malheureusement, la carte est aussi pivotée selon les deux autres axes, donc c’est un peu plus compliqué…

    J’ai trouvé dans ces deux articles (ici et ) ces formules, qui convertissent l’accélération en inclinaison (en radians, où atan2 est une variante de la fonction arc tangente qui donne un angle entre \(-\pi\) et \(\pi\) (au lieu de \(-\frac{\pi}{2}\) et \(\frac{\pi}{2}\)).

    \[\begin{split}\begin{array}{rcl} angleX &=& \operatorname{atan2}\left(-x, z\right)\\ angleY &=& \operatorname{atan2}\left(-y, z\right)\\ \end{array}\end{split}\]
  1. Au lieu d’incliner la carte, dans mes calculs, j’incline le plan horizontal selon les axes x et y. La droite marquant l’horizontale est donc l’intersection du plan horizontal avec le plan de la carte.

    • Le plan de la carte est celui d’équation \(z=0\).
    • Le plan de l’horizontale, qui a été incliné selon des angles \(angleX\) et \(angleY\) est le plan passant par les trois points de coordonnées : \(\left(0 ;0 ;0 \right)\), \(\left(\cos angleX ; 0 ; \sin angleX \right)\), \(\left(0 ; \cos angleY ; \sin angleY \right)\).

    L’équation de la droite est donc :

    \[\sin(angleX) \times \cos(angleY) + \cos(angleX) \times \sin(angleY) = 0\]
  2. Enfin, le tracé de la droite se fait dans la fonction tracedroite() (qui prend en argument les coefficients a et b de l’équation cartésienne ax+by=0 ; il n’y a pas de constante c puisque la droite passe par l’origine).

    Selon le coefficient directeur de la droite (dont la valeur absolue est plus grande ou plus petite que 1), on calcule, pour chaque valeur de x (ou de y), la valeur de l’autre coordonnées correspondante en utilisant l’équation. Ceci est fait avec un décalage de 2 sur chacun des deux axes, puisque dans nos calculs, la droite passe par l’origine, alors que sur la carte, elle passe par le pixel de coordonnées \((2;2)\).

  3. C’est un peu cracra. Il y a la moitié de ce raisonnement que je comprends à moitié. Il y a des incohérences (notamment les angles dont le 0 est l’horizontale ou la verticale, selon les cas). Mais ça marche.

 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
# Copyright 2019 Louis Paternault
#
# This file is part of Jouets.
#
# Jouets is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Jouets is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Jouets.  If not, see <http://www.gnu.org/licenses/>.

"""Trace une ligne horizontale."""

from microbit import *
import math

CROIX = Image("90009:09090:00900:09090:90009")


def tracedroite(a, b):
    """Trace une droite d'équation cartésienne ax+by=0"""
    display.clear()
    if a == b == 0:
        display.show(CROIX)
    elif abs(a) < abs(b):
        for x in range(-2, 3):
            display.set_pixel(x + 2, round(-a * x / b) + 2, 9)
    else:  # abs(b) < abs(a)
        for y in range(-2, 3):
            display.set_pixel(round(-b * y / a) + 2, y + 2, 9)


while True:
    # Récupère les données de l'accéléromètre
    x = accelerometer.get_x()
    y = accelerometer.get_y()
    z = accelerometer.get_z()

    # Convertit les mesures de l'accéléromètre en angles
    angleX = math.atan2(-x, z)
    angleY = math.atan2(-y, z)

    # Trace la droite horizontale
    tracedroite(
        math.sin(angleX) * math.cos(angleY), math.cos(angleX) * math.sin(angleY)
    )