Tracker solaire DIY perturbé par perte Wifi

Avec cette nouvelle donne, je doit ajouter 2 fils (ENA et ENB) au 3.3v de mon ESP qui est déjà surcharger.

Est-ce qu’il y aurait un moyen, sous ESPHome, pour affecter à un GPIO un état haut (3.3v) en permanence ?

Voici la réponse :

esphome:
  on_boot:
    - priority: 600
      then:
        - output.turn_on: moteur_enable

# Définition des sorties PWM pour le pont en H
output:
  # Pin A du pont en H (direction 1)
  - platform: ledc
    id: moteur_pin_a
    pin: GPIO04
    frequency: 40000Hz
    
  # Pin B du pont en H (direction 2)  
  - platform: ledc
    id: moteur_pin_b
    pin: GPIO05
    frequency: 40000Hz
    
  # Pin Enable du pont en H
  - platform: gpio
    id: moteur_enable
    pin: GPIO26

Le GPIO26 devient une borne 3.3v :wink:

Tu peux mettre en place un Output Component — ESPHome en mode binary.

Ou un switch que tu mets par défaut à ALWAYS_ON. Qui pourrait te servir comme ON/OFF de tes vérins.

Bonne nouvelle !!!

Le coffret est raccordé au traqueur physique, fini les tests sur table :grin:

Reste à étalonner tout ça, notamment le offset_azimuth dont je n’ai pas compris comment il était récupéré :thinking:

Tout l’asservissement repose sur la bonne orientation de l’axe du Roulis sur le Nord-Sud.

l’offset_azimut te permet de corriger un potentiel écart.

Comment tu as pu le calculer ?

à l’aide d’une boussole

@Scorpix , j’ai un soucis avec la position du traqueur sur l’axe E/O (Tangage), j’ai l’impression qu’il est à « l’envers ».

Pour appliquer les « - » dont tu parlais :

Où je dois mettre ces « - », en sachant que j’ai ces données en alignant « à l’œil » les panneaux avec le soleil :

PV roulis : -30.8 °
PV tangage : 31.3 °
sunRoulis : -39.8 °
sunTangage : -32.1 °

Si tu as conservé le même code que tu as mis plus haut, et qu’il n’y a que le tangage à l’envers, tu peux essayer de supprimer le ‹ - › que tu as mis devant id(accel_x).state

Je n’arrive pas à comprendre comment étalonner le tout … :sob:

Voici ce que j’ai comme retour sur l’IHM Web de ESPHome :

Et les données de mon capteur IMU :

Et voici les paramètres que j’ai configuré pour le code :

Avec la position de mon traqueur :

(Photo prise avec le nord dans le dos)

(Photo prise avec l’Est dans le dos)

On peut voir le MPU6050 collé sur la traverse (N/S) :

Le Z+ est au dessus en direction du ciel, le X+ en direction de l’Est et le Y+ en direction du Nord.

Je sèche :thinking:

Quel est le problème ?

Les valeurs que tu montres semblent cohérentes.

Sauf sur Z, s’il est pointé vers le ciel, tu devrais avoir une valeur négative.
Tu sembles avoir retiré le `multiply: -1` que j’avais mis dans mon code initial.

J’ai remonté la manip sur table pour pouvoir investiguer, et j’ai comparé avec le montage de ma MPU6050 dehors.

J’ai introduit une erreur plus haut dans l’orientation des axes. X colinéaire à Nord/Sud et Y à Est/Ouest.

Sinon, j’ai comparé les marquages indiquées sur la MPU6050, il semble y avoir une incohérence, car l’axe X qu’ils indiquent, retournent une valeur négative. Leur trièdre n’est pas direct.

Vu qu’on a la même MPU, pour comparer.
En suivant les marquages sur la MPU, j’ai l’axe X vers le SUD, Y vers l’OUEST, et les composants soudés (car Z non indiqué) vers le SOL.

Vu ta dernière photo, je pense que ta carte est inversé (c’est plutôt moi qui l’est soudée à l’envers). Donc essaies d’utiliser le code suivant, j’ai corrigé rapidement pour être compatible de ta conf, pour que ce soit plus lisible, j’ai tout supprimé, prends en compte que les filters et lambda.:

- platform: mpu6050
    address: 0x68
    accel_x:
      id: accel_x
      filters:
        - offset: $offset_accX

    accel_y:
      id: accel_y
      filters:
        - multiply: -1.0
        - offset: $offset_accY
 
    accel_z:
      id: accel_z
      filters:
        - offset: $offset_accZ


  - platform: template
    id: PV_roulis
    lambda: return atan2(id(accel_y).state, id(accel_z).state)*180/$PI;

            
  - platform: template
    id: PV_tangage
    lambda: return atan2(id(accel_x).state, id(accel_z).state)*180/$PI;

Quand les panneaux regardent vers le SUD, le tangage est négatif, vers le NORD c’est positif.
Quand les panneaux regardent vers le OUEST, le roulis est négatif, vers le EST c’est positif.

J’ai modifier le code comme indiqué :

Ensuite, j’ai repris la calibration du capteur car une fois passé en mode automatique, il a bougé vers le soleil mais c’est arrêté un peu tôt.

J’ai donc fait la calibration pour trouvé les offsets comme ceci :

Le panneau de niveau dans les 2 directions (N/S, E/O), vérifié à l’aide d’un niveau à bulle.

Le capteur dans cette position (Z+ en haut, Y+ vers le nord, X+ vers l’est) :

Récupération de l’offset = 9.81 - id(accel_z).state

Ensuite, position du traqueur inchangé, juste déplacement du capteur comme ceci (Z+ vers le sud, Y+ vers le bas, X+ vers l’ouest) :

Récupération de l’offset = 9.81 - id(accel_y).state

Ensuite, position du traqueur inchangé, juste déplacement du capteur comme ceci (Z+ vers le sud, Y+ vers l’ouest, X+ vers le haut) (désolé pas de photo).

Récupération de l’offset = 9.81 - id(accel_x).state

Ce qui donne des offsets comme ceci :

  offset_accX: '0.02'
  offset_accY: '0.68'
  offset_accZ: '-0.05'

Upload des nouvelles valeurs, mise en automatique … Il passe en mode manuel avec ces infos :

Avec cette position :

Les vérins devraient être sorti sur l’axe N/S (Tangage) et un peu plus sorti vers l’Ouest (Roulis).

tu sembles avoir une inversion d’angle. Tu as essayé avec cette configuration ? Et en même temps en appliquant la modification des signes dans le code ?

J’ai inversé le capteur IMU avec Z+ vers le sol, X+ vers le sud et Y+ vers l’ouest.

Dans cette position, voici les valeurs relevées :

Avec ce code :

substitutions:
  angle_min_roulis: '-60.0'
  angle_max_roulis: '60.0'
  angle_min_tangage: '35.0'
  angle_max_tangage: '53.0'

sensor:
  - platform: mpu6050
    address: 0x68
    update_interval: 500ms

    accel_x:
      id: accel_x
      name: "MPU Accel X"
      filters:
        - offset: $offset_accX
    accel_y:
      id: accel_y
      name: "MPU Accel Y"
      filters:
        - multiply: -1.0
        - offset: $offset_accY
    accel_z:
      id: accel_z
      name: "MPU Accel Z"
      filters:
        - offset: $offset_accZ
  - platform: template
    id: PV_roulis
    name: Roulis PV
    internal: $KEEP_INTERNE
    unit_of_measurement: °
    update_interval: $boucle_asservissement
    lambda: return atan2(id(accel_y).state, id(accel_z).state)*180/$PI;
    filters:
      - offset : $offset_roulis
    on_value_range:
      - above: $angle_max_roulis
        then:
          - switch.turn_on: manual_mode
      - below: $angle_min_roulis
        then:
          - switch.turn_on: manual_mode
            
  - platform: template
    id: PV_tangage
    name: Tangage PV
    internal: $KEEP_INTERNE
    unit_of_measurement: °
    update_interval: $boucle_asservissement
    lambda: return atan2(id(accel_x).state, id(accel_z).state)*180/$PI;
    filters:
      - offset : $offset_tangage
    on_value_range:
      - above: $angle_max_tangage
        then:
          - switch.turn_on: manual_mode
      - below: $angle_min_tangage
        then:
          - switch.turn_on: manual_mode

Je n’ai pas pu faire d’autre tests car il fait nuit :unamused:

désolé je ne suis pas très clair.

Du coup, là sur ta photo (avec le fil de l’imu sortant vers le haut), tu es comme moi, dont il faut -1 sur Z, et rien sur x et y.

accel_x:
      id: accel_x
      name: "MPU Accel X"
      filters:
        - offset: $offset_accX
    accel_y:
      id: accel_y
      name: "MPU Accel Y"
      filters:
        - offset: $offset_accY
    accel_z:
      id: accel_z
      name: "MPU Accel Z"
      filters:
        - multiply: -1.0
        - offset: $offset_accZ

Dans le cas où tu voulais conserver ton fil partant de ton IMU vers le bas, avec x vers sud et y vers est, alors

accel_x:
      id: accel_x
      name: "MPU Accel X"
      filters:
        - offset: $offset_accX
    accel_y:
      id: accel_y
      name: "MPU Accel Y"
      filters:
        - multiply: -1.0
        - offset: $offset_accY
    accel_z:
      id: accel_z
      name: "MPU Accel Z"
      filters:
        - offset: $offset_accZ

Je suis rester dans cette situation, avec le câble qui sort vert le haut, j’ai mis ce code :

# ESPHome configuration file for 
# solar-tracker module
# https://forum.hacf.fr/t/tracker-solaire-diy-perturbe-par-perte-wifi/47291/18

substitutions:
  esphome_name: solar-tracker
  logger_level: INFO
  logger_baud_rate: '0'
  static_ip: !secret ip_solar_tracker
  power_save_mode: none


  # CONSTANTES D'INSTALLATION
  HOME_LAT: xx.xxxxx
  HOME_LON: xx.xxxxx

  angle_min_roulis: '-60.0'       # Butée physique de l'angle minimum en degré que peut atteindre le roulis
  angle_max_roulis: '60.0'        # Butée physique de l'angle maximum en degré que peut atteindre le roulis
  angle_min_tangage: '35.0'       # Butée physique de l'angle minimum en degré que peut atteindre le tangage
  angle_max_tangage: '53.0'       # Butée physique de l'angle maximum en degré que peut atteindre le tangage
  boucle_asservissement: '100ms'  # vitesse de la boucle d'asservissement
  boucle_mesure: '10s'            # vitesse de la boucle de mesure des roulis et tangage
  max_speed_offset: '12.0'        # si la consigne est à plus de 12°, vitesse vérin à 100%
  offset_accX: '0.02'             # Calibration grossière de l'IMU, à faire sur table nivelé au tout début
  offset_accY: '0.68'             # Calibration grossière de l'IMU, à faire sur table nivelé au tout début
  offset_accZ: '-0.05'            # Calibration grossière de l'IMU, à faire sur table nivelé au tout début
  offset_anemo: 0                 # Calibration de l'anémomètre
  offset_azimuth: '-5.0'          # mon système fonctionne qui si tu as l'axe du roulis colinéaire avec l'axe Nord-Sud, ça permet d'ajuster l'erreur
  offset_tangage: '0.0'           # permet d'ajuster des erreurs sur le tangage
  offset_roulis: '0.0'            # permet d'ajuster des erreurs sur le roulis
  precision_offset: '2.0'         # angle cône de suivi du soleil
  rapport_kmh_v: 90               # Rapport entre la vitesse du vent relevé par l'anémomètre et la tension relevée (1v - 25m/s => 90 km/h)
  repos_tangage: '-30.0'          # angle tangage repos mode Nuit/Tempête par rapport à l'horizontal
  repos_roulis: '-20.0'           # angle roulis repos mode Nuit/Tempête par rapport à l'horizontal

  vitesse_mini_verins: '60'       # Vitesse minimales d'approche des vérins
  
  PUSHED_TO_HA: 'False'
  KEEP_INTERNE: 'True'            # Basculer cette constante à False pour faire remonter tous les sensors dans HA
  PI: '3.14159265359'
  
  # GPIO
  GPIO_FREQ_PWM: '40000Hz'
  GPIO_SDA: '21'
  GPIO_SCL: '22'

packages:
  base: !include .config-base.yaml
  wifi: !include .config-wifi.yaml
  ota: !include .config-ota.yaml
  logger: !include .config-logger.yaml
  portal: !include .config-portal.yaml
  api: !include .config-api.yaml
  status: !include .config-status.yaml
  web_server: !include .config-web-server.yaml
  # mqtt: !include .config-mqtt.yaml

esp32:
  board: esp32dev



# Module Definition

# Définition de la communication I2C pour le capteur MPU6050
i2c:
  sda: 
    number: ${GPIO_SDA}
  scl: 
    number: ${GPIO_SCL}
  scan: true
  id: bus_a

# Définition des sorties PWM pour le H-Bridge DBH-12V
output:
  # Moteur A = Tangage
  # Moteur A Pin IN1A du pont en H (IN1A <=> GPIO13)
  - platform: ledc
    id: tangage_pin_IN1A
    pin: GPIO13
    frequency: ${GPIO_FREQ_PWM}

  # Moteur A Pin B du pont en H (IN2A <=> GPIO12)
  - platform: ledc
    id: tangage_pin_IN2A
    pin: GPIO12
    frequency: ${GPIO_FREQ_PWM}

  # Moteur B = Roulis
  # Moteur B Pin A du pont en H (IN1B <=> GPIO14)
  - platform: ledc
    id: roulis_pin_IN1B
    pin: GPIO14
    frequency: ${GPIO_FREQ_PWM}

  # Moteur B Pin B du pont en H (IN2B <=> GPIO27)
  - platform: ledc
    id: roulis_pin_IN2B
    pin: GPIO27
    frequency: ${GPIO_FREQ_PWM}
    
# Dans Esphome, le pilotage des vérins à travers un pont en H, se fait avec la classe FAN.
# Option: 
#   un nombre incrémental à chaque action des vérins pour avoir une idée du nombre de fois
#   par jour qu’ils sont mis en action.
# Configuration du moteur via le composant fan hbridge
fan:
  # Moteur A
  - platform: hbridge
    id: tangage_verin
    name: "Verin Tangage - H-Bridge"
    pin_a: tangage_pin_IN1A
    pin_b: tangage_pin_IN2A
    decay_mode: SLOW
    internal: ${PUSHED_TO_HA}
    on_turn_on: 
      then:
        - number.increment: number_tangage

  # Moteur B
  - platform: hbridge
    id: roulis_verin
    name: "Verin Roulis - H-Bridge"
    pin_a: roulis_pin_IN1B
    pin_b: roulis_pin_IN2B
    decay_mode: SLOW
    internal: ${PUSHED_TO_HA}
    on_turn_on: 
      then:
        - number.increment: number_roulis

# Boucle d'asservissement des positions des vérins
# Arguments :
#   - offset : écart entre la position du soleil et la position réel des panneaux sur l'axe choisi
# Description :
#   En fonction du signe, le pilotage se fait dans un sens ou dans l'autre (REVERSE/FORWARD).
#   En fonction de la valeur, la vitesse des vérins est plus ou moins importante. Plus l'écart est
#   important, plus la vitesse d'approche est grande, plus on s'approche de la consigne, plus la 
#   vitesse est lente (ceci pour éviter les chocs brutaux). Plus la $boucle_asservissement est petite,
#   plus l'approche sera douce.
#   Une vitesse minimale (vitesse_mini_verins) est défini pour assurer un bon fonctionnement des vérins.
#   Cette vitesse minimale dépend du vérin, elle est défini par expérimentation.
# Rappel :
#   - Roll  : Roulis
#   - Pitch : Tangage
script:
  - id: RollPilot
    mode: single
    parameters:
      offset: float
    then:
      - lambda: |-
          if (abs(offset)>$precision_offset) {
            int speed = 0;
            if(abs(offset)>$max_speed_offset) {
              speed = 100;
            }
            else {
              speed = ${vitesse_mini_verins} + (40*abs(offset)/$max_speed_offset);
            }
            if (offset>0) {
              auto call = id(roulis_verin).turn_on();
              call.set_speed(speed);
              call.set_direction(FanDirection::FORWARD);
              call.perform();
            } else {
              auto call = id(roulis_verin).turn_on();
              call.set_speed(speed);
              call.set_direction(FanDirection::REVERSE);
              call.perform();
            }
          }
          else {
            auto call = id(roulis_verin).turn_off();
            call.perform();
          }
  - id: PitchPilot
    mode: single
    parameters:
      offset: float
    then:
      - lambda: |-
          if (abs(offset)>$precision_offset) {
            int speed = 0;
            if(abs(offset)>$max_speed_offset) {
              speed = 100;
            }
            else {
              speed = ${vitesse_mini_verins} + (40*abs(offset)/$max_speed_offset);
            }
            if (offset>0) {
              auto call = id(tangage_verin).turn_on();
              call.set_speed(speed);
              call.set_direction(FanDirection::FORWARD);
              call.perform();
            } else {
              auto call = id(tangage_verin).turn_on();
              call.set_speed(speed);
              call.set_direction(FanDirection::REVERSE);
              call.perform();
            }
          }
          else {
            auto call = id(tangage_verin).turn_off();
            call.perform();
          }

# Boutons de contrôle manuel
button:
  # Bouton pour faire avancer le Verin N/S rapidement
  - platform: template
    name: "Verin N/S - Action - Avance - 80 %"
    on_press:
      - fan.turn_on:
          id: tangage_verin
          speed: 80
          direction: FORWARD

  # Bouton pour faire avancer le Verin N/S lentement
  - platform: template
    name: "Verin N/S - Action - Avance - 20 %"
    on_press:
      - fan.turn_on:
          id: tangage_verin
          speed: 20
          direction: FORWARD

  # Bouton pour faire reculer le Verin N/S rapidement
  - platform: template
    name: "Verin N/S - Action - Recule - 80 %"
    on_press:
      - fan.turn_on:
          id: tangage_verin
          speed: 80
          direction: REVERSE

  # Bouton pour faire reculer le Verin N/S lentement
  - platform: template
    name: "Verin N/S - Action - Recule - 20 %"
    on_press:
      - fan.turn_on:
          id: tangage_verin
          speed: 20
          direction: REVERSE

  # Bouton d'arrêt du Verin N/S
  - platform: template
    name: "Verin N/S - Action - Stop"
    on_press:
      - fan.turn_off: tangage_verin

  # Bouton pour faire tourner le Verin E/O vers l'avant rapidement
  - platform: template
    name: "Verin E/O - Action - Avance - 80 %"
    on_press:
      - fan.turn_on:
          id: roulis_verin
          speed: 80
          direction: FORWARD

  # Bouton pour faire tourner le Verin E/O vers l'avant lentement
  - platform: template
    name: "Verin E/O - Action - Avance - 20 %"
    on_press:
      - fan.turn_on:
          id: roulis_verin
          speed: 20
          direction: FORWARD

  # Bouton pour faire tourner le Verin E/O vers l'arrière rapidement
  - platform: template
    name: "Verin E/O - Action - Recule - 80 %"
    on_press:
      - fan.turn_on:
          id: roulis_verin
          speed: 80
          direction: REVERSE

  # Bouton pour faire tourner le Verin E/O vers l'arrière lentement
  - platform: template
    name: "Verin E/O - Action - Recule - 20 %"
    on_press:
      - fan.turn_on:
          id: roulis_verin
          speed: 20
          direction: REVERSE

  # Bouton d'arrêt du Verin E/O
  - platform: template
    name: "Verin E/O - Action - Stop"
    on_press:
      - fan.turn_off: roulis_verin

# Capteur de statut du moteur
binary_sensor:
  - platform: template
    name: "Verin N/S - Etat - En marche"
    lambda: |-
      return id(tangage_verin).state;
  - platform: template
    name: "Verin E/O - Etat - En marche"
    lambda: |-
      return id(roulis_verin).state;

# Description :
#   Affichage MAC Address pour debugging
# text_sensor:
#   - platform: wifi_info
#     mac_address:
#       name: $device_name_friendly MAC Address
#       id:   text_sensor_mac_address

# Incréments des actions des vérins
# Description :
#   Ces nombres sont créés pour connaitre le nombre de fois qu'un vérin est actionné. Ces compteurs
#   sont remis à 0 en fin de journée par la classe SUN. Il peuvent être remontés à HA via l'attribut
#   'internal' en le passant de 'KEEP_INTERNE' à 'PUSHED_TO_HA'
number:
  - platform: template
    internal: $KEEP_INTERNE
    id: number_tangage
    restore_value: True
    min_value: 0
    max_value: 9999
    step: 1
    optimistic: True
    on_value: 
      then:
        - lambda: "return id(sensor_number_tangage).publish_state(x);"

  - platform: template
    id: number_roulis
    internal: $KEEP_INTERNE
    restore_value: True
    min_value: 0
    max_value: 9999
    step: 1
    optimistic: True
    on_value: 
      then:
        - lambda: "return id(sensor_number_roulis).publish_state(x);"

# Déclaration de capteurs
sensor:
  # Description :
  #   Récupération de la tension sur l'anémomètre
  # Utilisation :
  #   - calcul de la vitesse du vent 'vent_kmh'
  - platform: adc
    pin: GPIO34
    name: "Anémomètre"
    id: anemo_tension
    internal: $KEEP_INTERNE
    filters:
    - offset : $offset_anemo
    - clamp:
        min_value: 0.1
        max_value: 3.0
        ignore_out_of_range: False
    attenuation : 12db # Range 0,075 V ~ 3,12 V
    accuracy_decimals: 2
    unit_of_measurement: V
    update_interval: $boucle_asservissement

  # Description :
  #   Déclaration des capteurs d'actions des vérins.
  # Utilisation :
  #   Ces capteurs sont utilisés par les numbers 'number_roulis' et 'number_tangage'
  - platform: template
    name: action verin roulis
    id: sensor_number_roulis

  - platform: template
    name: action verin tangage
    id: sensor_number_tangage

  # Description
  #   Déclaration des capteurs d'accélération du MPU6050
  # Paramètrages :
  #   - address         : adresse du capteur sur le bus I2C
  #   - update_interval : intervalle de vérification du capteur. Tous les capteurs du
  #                       MPU6050 seront rafraichis à cette fréquence.
  - platform: mpu6050
    address: 0x68
    update_interval: 500ms

    # Description
    #   Déclaration des capteurs d'accélération du MPU6050
    # Utilisation :
    #   Ces capteurs 'accel_x', 'accel_y', 'accel_z' sont utilisés pour le calcul des
    #   angles des panneaux dans les capteurs 'PV_roulis' et 'PV_tangage'
    accel_x:
      id: accel_x
      name: "MPU Accel X"
      filters:
        - offset: $offset_accX
      #  - sliding_window_moving_average:
      #     window_size: 10
      #     send_every: 5
    accel_y:
      id: accel_y
      name: "MPU Accel Y"
      filters:
        - offset: $offset_accY
      #  - sliding_window_moving_average:
      #     window_size: 10
      #     send_every: 5
    accel_z:
      id: accel_z
      name: "MPU Accel Z"
      filters:
        - multiply: -1.0
        - offset: $offset_accZ
      #  - sliding_window_moving_average:
      #     window_size: 10
      #     send_every: 5

  # Description
  #   Déclaration du capteur de température du MPU6050
  # Utilisation :
  #   Ce capteur est utilisé pour remonter la température à HA par l'intermédiaire
  #   du capteur 'MPU température'
    temperature:
      id: MPU_temp
      name: "solar-tracker Temperature"
      filters:
       - sliding_window_moving_average:
          window_size: 10
          send_every: 5

  # Description
  #   Calcul de l'offset
  # Utilisation :
  #   Le calcul des offset permet d'étalonner le capteur pour qu'il indique les bonnes
  #   valeurs d'accélération en m/s² une fois positionner sur l'installation.
  #   Une fois le capteur IMU positionné sur le traqueur, et le traqueur en 
  #   position horizontale avec l'axe Z colinéaire avec l'axe vertical, l'axe des X
  #   colinéaire avec l'axe Nord/Sud et l'axe des Y colinéaire avec l'axe Est/Ouest, 
  #   relevez ces valeurs d'offset.
  #   Ces capteurs ne servent qu'à l'étalonnage, il faut les commenter une fois 
  #   l'étalonnage effectué.
  - platform: template
    id: accel_x_offset
    name: "MPU Accel X offset"
    unit_of_measurement: m/s²
    accuracy_decimals: 2
    update_interval: $boucle_asservissement
    lambda: return 9.81 - id(accel_x).state;
  - platform: template
    id: accel_y_offset
    name: "MPU Accel Y offset"
    unit_of_measurement: m/s²
    accuracy_decimals: 2
    update_interval: $boucle_asservissement
    lambda: return 9.81 - id(accel_y).state;
  - platform: template
    id: accel_z_offset
    name: "MPU Accel Z offset"
    unit_of_measurement: m/s²
    accuracy_decimals: 2
    update_interval: $boucle_asservissement
    lambda: return 9.81 - id(accel_z).state;

  # Description
  #   Déclaration des capteurs d'accélération du MPU6050 corrigé par l'offset
  # Utilisation :
  #   Ces capteurs 'accel_x', 'accel_y', 'accel_z' sont utilisés pour l'étalonnage 
  #   des valeurs d'offset.
  #   Une fois les offsets renseignés (voir plus haut 'Calcul de l'offset'), vérifiez
  #   que les valeurs remontées par ces capteurs sont bien 9.81 m/s² lorsque le traqueur
  #   est en position à plat.
  - platform: template
    id: accel_x_corrected
    name: "MPU Accel X with offset"
    unit_of_measurement: m/s²
    accuracy_decimals: 2
    update_interval: $boucle_asservissement
    lambda: return id(accel_x).state + $offset_accX;
  - platform: template
    id: accel_y_corrected
    name: "MPU Accel Y with offset"
    unit_of_measurement: m/s²
    accuracy_decimals: 2
    update_interval: $boucle_asservissement
    lambda: return id(accel_y).state + $offset_accY;
  - platform: template
    id: accel_z_corrected
    name: "MPU Accel Z with offset"
    unit_of_measurement: m/s²
    accuracy_decimals: 2
    update_interval: $boucle_asservissement
    lambda: return id(accel_z).state + $offset_accZ;

  # Description
  #   Calcul de l'angle des panneaux par rapport à l'horizontal sur l'axe E/O.
  #   Ce capteur est calculé à la fréquence définie par la variable 'boucle_asservissement'
  #   , souvent très rapide, quelques millsecondes. Pour éviter la surcharge du WiFi, on les
  #   garde en interne de l'ESP par 'internal: $KEEP_INTERNE'.
  #   Si l'angle calculé n'est pas compris entre les butées logicielles 'angle_min_roulis'
  #   'angle_max_roulis', le mode manuel est activé, ce qui inhibe l'asservissement. Ceci pour
  #   protéger la mécanique des vérins si, par exemple, le capteur tombe.
  # Utilisation :
  #   - Remonté dans HA via le capteur 'PV roulis'
  #   - Par le capteur 'OffsetRoll'
  - platform: template
    id: PV_roulis
    name: Roulis PV
    internal: $KEEP_INTERNE
    unit_of_measurement: °
    update_interval: $boucle_asservissement
    # lambda: return atan2(id(accel_y).state, id(accel_z).state)*180/$PI;
    lambda: return atan2(id(accel_y).state, id(accel_z).state)*180/$PI;
    filters:
      - offset : $offset_roulis
    on_value_range:                       # si calcul d'un angle supérieur au réalisable mécanique, alors problème, arrêt de l'asservissement
      - above: $angle_max_roulis          # 60.0 
        then:
          - switch.turn_on: manual_mode
      - below: $angle_min_roulis          # -60.0
        then:
          - switch.turn_on: manual_mode
            
  # Description
  #   Calcul de l'angle des panneaux par rapport à l'horizontal sur l'axe N/S.
  #   Ce capteur est calculé à la fréquence définie par la variable 'boucle_asservissement'
  #   , souvent très rapide, quelques millsecondes. Pour éviter la surcharge du WiFi, on les
  #   garde en interne de l'ESP par 'internal: $KEEP_INTERNE'.
  #   Si l'angle calculé n'est pas compris entre les butées logicielles 'angle_min_tangage'
  #   'angle_max_tangage', le mode manuel est activé, ce qui inhibe l'asservissement. Ceci pour
  #   protéger la mécanique des vérins si, par exemple, le capteur tombe.
  # Utilisation :
  #   - Remonté dans HA via le capteur 'PV tangage'
  #   - Par le capteur 'OffsetPitch'
  - platform: template
    id: PV_tangage
    name: Tangage PV
    internal: $KEEP_INTERNE
    unit_of_measurement: °
    update_interval: $boucle_asservissement
    # lambda: return atan2(-id(accel_x).state, id(accel_z).state)*180/$PI;
    lambda: return atan2(id(accel_x).state, id(accel_z).state)*180/$PI;
    filters:
      - offset : $offset_tangage
    on_value_range:                       # si calcul d'un angle supérieur au réalisable mécanique, alors problème, arrêt de l'asservissement
      - above: $angle_max_tangage         # 35.0
        then:
          - switch.turn_on: manual_mode
      - below: $angle_min_tangage         # -53.0
        then:
          - switch.turn_on: manual_mode

  # Description
  #   Ces capteurs sont des copies des capteurs qui sont remonter dans HA à la fréquence choisie
  #   par la variable 'boucle_mesure'
  # Utilisation :
  #   - Remontés dans HA
  - platform: template
    name: Roulis PV
    unit_of_measurement: °
    accuracy_decimals: 1
    update_interval: $boucle_mesure
    lambda: return id(PV_roulis).state;

  - platform: template
    name: Tangage PV
    unit_of_measurement: °
    accuracy_decimals: 1
    update_interval: $boucle_mesure
    lambda: return id(PV_tangage).state;

  - platform: template
    name: MPU température
    device_class: temperature
    update_interval: 60s
    lambda: return id(MPU_temp).state;

  - platform: template
    name: Vitesse vent
    unit_of_measurement: Km/h
    accuracy_decimals: 0
    update_interval: $boucle_mesure
    lambda: return id(vent_kmh).state;

  # Description
  #   Calcul de l'offset du roulis entre la valeur du soleil et la valeur des panneaux.
  #   Ce calcul est effectué à la fréquence prévue par la variable 'boucle_asservissement'.
  #   L'offset calculé est transmis au script RollPilot uniquement si le fonctionnement
  #   n'est pas en mode manuel.
  #   Ce calcul n'est pas remonté à HA ('internal: $KEEP_INTERNE')
  # Utilisation :
  #   - script RollPilot
  - platform: template
    id: OffsetRoll
    name: Roulis Offset
    internal: $PUSHED_TO_HA
    update_interval: $boucle_asservissement
    lambda: return id(PV_roulis).state - id(sunRoulis).state;
    on_value: 
      - if:
          condition:
            - switch.is_off: manual_mode # vérification du mode manuel, si ON alors pas de pilotage
          then:
            - lambda: id(RollPilot)->execute(x);

  # Description
  #   Calcul de l'offset du tangage entre la valeur du soleil et la valeur des panneaux.
  #   Ce calcul est effectué à la fréquence prévue par la variable 'boucle_asservissement'.
  #   L'offset calculé est transmis au script PitchPilot uniquement si le fonctionnement
  #   n'est pas en mode manuel.
  #   Ce calcul n'est pas remonté à HA ('internal: $KEEP_INTERNE')
  # Utilisation :
  #   - script PitchPilot
  - platform: template
    id: OffsetPitch
    name: Tangage Offset
    internal: $PUSHED_TO_HA
    update_interval: $boucle_asservissement
    lambda: return id(PV_tangage).state - id(sunTangage).state;
    on_value: 
      - if:
          condition:
            - switch.is_off: manual_mode # vérification du mode manuel, si ON alors pas de pilotage
          then:
            - lambda: id(PitchPilot)->execute(x);

  # Description
  #   Récupération de l'élévation du soleil en bornant sa valeur via le filtre 'clamp'.
  #   Toute valeur inférieure sera bornée par la valeur de 'min_value'.
  #   Toute valeur supérieure sera bornée par la valeur de 'max_value'.
  #   Les valeurs de 'min_value' et 'mxa_value' sont à définir en fonction de l'emplacement
  #   géographique du panneau.
  #   Ce calcul n'est pas remonté à HA ('internal: $KEEP_INTERNE')
  # Utilisation :
  #   - capteurs sunX, sunY et sunZ
  - platform: sun
    name: Sun Elevation
    id: sunElevation
    type: elevation
    internal: $PUSHED_TO_HA
    filters: 
#      - lambda: |-
#          if(isnan(x)){return {};}
#          else{return x;}
      - clamp:
          min_value: 05
          max_value: 89
          ignore_out_of_range: False
      
  # Description
  #   Récupération de l'azimuth du soleil en bornant sa valeur via le filtre 'clamp'.
  #   Toute valeur inférieure sera bornée par la valeur de 'min_value'.
  #   Toute valeur supérieure sera bornée par la valeur de 'max_value'.
  #   Les valeurs de 'min_value' et 'max_value' sont à définir en fonction de l'emplacement
  #   géographique du panneau.
  #   Ce calcul n'est pas remonté à HA ('internal: $KEEP_INTERNE')
  # Utilisation :
  #   - capteurs sunX et sunY
  - platform: sun
    name: Sun Azimuth
    id: sunAzimuth
    type: azimuth
    internal: $PUSHED_TO_HA
    filters: 
#      - lambda: |-
#          if(isnan(x)){return {};}
#          else{return x;}
      - offset: $offset_azimuth
      - clamp:
          min_value: 60
          max_value: 310
          ignore_out_of_range: False

  # Description
  #   Calcul de la position du soleil dans le même repère que le capteur MPU6050.
  #   Ce calcul est effectué à la fréquence choisie par la variable 'boucle_mesure'
  #   Ce calcul n'est pas remonté à HA ('internal: $KEEP_INTERNE')
  # Utilisation :
  #   - capteurs sunRoulis et sunTangage
  - platform: template
    id: sunX
    name: sunX
    internal: $PUSHED_TO_HA
    lambda: return  cos(id(sunElevation).state*$PI/180)*cos(id(sunAzimuth).state*$PI/180);
    update_interval: $boucle_mesure

  - platform: template
    id: sunY
    name: sunY
    internal: $PUSHED_TO_HA
    lambda: return  -cos(id(sunElevation).state*$PI/180)*sin(id(sunAzimuth).state*$PI/180);
    update_interval: $boucle_mesure

  - platform: template
    id: sunZ
    name: sunZ
    internal: $PUSHED_TO_HA
    lambda: return  sin(id(sunElevation).state*$PI/180);
    update_interval: $boucle_mesure

  # Description
  #   Calcul de la position sur le roulis du soleil en dégré en bornant sa valeur via le filtre 'clamp'.
  #   Si le mode repos/tempête est activé, le calcul renverra la position de repos/tempête de roulis.
  #   Toute valeur inférieure sera bornée par la valeur de 'min_value'.
  #   Toute valeur supérieure sera bornée par la valeur de 'max_value'.
  #   Les valeurs de 'min_value' et 'max_value' sont les butées logicielles légérement inférieures
  #   au butées physiques définies par 'angle_min_roulis' et 'angle_max_roulis'.
  #   Si le soleil est en dehors de ces butées logicielles, l'asservissement est toujours actif
  #   mais en butée.
  #   Ce calcul est effectué à la fréquence de 10.1s (soit la variable boucle_messure + 0.1s)
  #   Ce calcul est remonté à HA ('internal: ${PUSHED_TO_HA}')
  # Utilisation :
  #   - capteurs OffsetRoll
  - platform: template
    id: sunRoulis
    name: Roulis soleil
    unit_of_measurement: °
    internal: ${PUSHED_TO_HA}
    update_interval: 10.1s
    lambda: |-
      if (id(storm_mode).state) return {$repos_roulis}; // Angle azimuth repos
      return -(-acos(id(sunY).state/sqrt( pow( id(sunY).state , 2) + pow( id(sunZ).state , 2)))*180/$PI+90);
    filters: 
      - clamp:
          min_value: -52
          max_value: 52
          ignore_out_of_range: False

  # Description
  #   Calcul de la position sur le tangage du soleil en dégré en bornant sa valeur via le filtre 'clamp'.
  #   Si le mode repos/tempête est activé, le calcul renverra la position de repos/tempête de tangage.
  #   Toute valeur inférieure sera bornée par la valeur de 'min_value'.
  #   Toute valeur supérieure sera bornée par la valeur de 'max_value'.
  #   Les valeurs de 'min_value' et 'max_value' sont les butées logicielles légérement inférieures
  #   au butées physiques définies par 'angle_min_tangage' et 'angle_max_tangage'.
  #   Si le soleil est en dehors de ces butées logicielles, l'asservissement est toujours actif
  #   mais en butée.
  #   Ce calcul est effectué à la fréquence de 10.1s (soit la variable boucle_messure + 0.1s)
  #   Ce calcul est remonté à HA ('internal: ${PUSHED_TO_HA}')
  # Utilisation :
  #   - capteurs OffsetPitch
  - platform: template
    id: sunTangage
    name: Tangage soleil
    unit_of_measurement: °
    internal: ${PUSHED_TO_HA}
    update_interval: 10.15s
    lambda: |-
      if (id(storm_mode).state) return {$repos_tangage}; // Angle elevation repos
      return asin(id(sunX).state)/sqrt( pow( id(sunX).state , 2) + pow( id(sunZ).state , 2))*180/$PI;
    filters: 
      - clamp:
          min_value: -50
          max_value: 30
          ignore_out_of_range: False
    
  - platform: internal_temperature
    name: "ESP Temperature"

  # Description :
  #   Calcul de la vitesse du vent en Km/h
  #   Cette vitesse du vent permet la mise en mode tempête (traqueur en position de sécurité).
  # Utilisation :
  #   - calcul de la vitesse du vent 'vent_kmh'
  - platform: template
    id: vent_kmh
    unit_of_measurement: Km/h
    internal: $KEEP_INTERNE
    update_interval: $boucle_asservissement
    lambda: return (id(anemo_tension).state)*$rapport_kmh_v;
    filters: 
    - clamp:
        min_value: 5
        max_value: 25               # 150
        ignore_out_of_range: False
    on_value_range:
      - above: 30
        then:
          - switch.turn_on: storm_mode

  # Description :
  #   Calcul de la vitesse du vent en Km/h
  #   Cette vitesse du vent permet la mise en mode tempête (traqueur en position de sécurité).
  # Utilisation :
  #   - calcul de la vitesse du vent 'vent_kmh'
  - platform: template
    name: Vent_kmh
    accuracy_decimals: 0
    unit_of_measurement: Km/h
    update_interval: $boucle_asservissement
    lambda: return id(vent_kmh).state;

# Description :
#   Déclaration des boutons
switch:
  # Description :
  #   Déclaration du bouton pour passer en mode manuel. Le passage en mode manuel coupera
  #   l'asservissement automatique des panneaux.
  #   Le mode 'optimistic: True' indique que action sur ce bouton lance immédiatement la mise à jour
  #   de son état
  # Utilisation :
  #   - OffsetRoll, OffsetPitch
  #   - PV_Roulis, PV_Tangage
  - platform: template
    id: manual_mode
    optimistic: True
    name: "Mode manuel"
    icon: "mdi:hand-back-right-outline"
    on_turn_on:
    - fan.turn_off: tangage_verin
    - fan.turn_off: roulis_verin

  # Description :
  #   Déclaration du bouton pour passer en mode repos/tempête. Le passage en mode repos/tempête enverra
  #   une position fictive du soleil qui forcera le panneau à se mettre en position repos.
  #   Le mode 'optimistic: True' indique que action sur ce bouton lance immédiatement la mise à jour
  #   de son état.
  # Utilisation :
  #   - sunRoulis, sunTangage
  - platform: template
    id: storm_mode
    name: "Mode nuit/intemperie"
    icon: "mdi:weather-lightning-rainy"
    optimistic: True
    on_turn_on:
    - lambda: return id(sunTangage).publish_state($repos_tangage);  # Angle elevation repos
    - lambda: return id(sunRoulis).publish_state($repos_roulis);    # Angle azimuth repos

# Description :
#   Récupération de l'heure de Home Assistant.
# Utilisation :
#   Obligatoire pour la récupération de la classe Sun
time:
  - platform: homeassistant

# Description :
#   Récupération de la position du soleil.
# Utilisation :
#   Utiliser pour les capteurs sunElevation et sunAzimuth
sun:
  latitude: ${HOME_LAT}
  longitude: ${HOME_LON}
  id: my_sun
  on_sunrise:
    - then:
      - switch.turn_off: storm_mode       # Asservir vers position du levée du soleil
  on_sunset:
    - then:
      - switch.turn_on: storm_mode        # Mettre en position de repos/vent à presque horizontal, avec légère pente pour écoulement pluie
      - number.to_min: number_roulis      # RàZ le soir
      - number.to_min: number_tangage     # RàZ le soir

Comme tu peux le voir, j’ai commenter les sliding_window_moving_average:, est-ce qu’il fallait ?

Et le panneau a bien bougé vers le soleil levant mais il est passé en mode manuel.

Et comme tu peux le voir, le vérin N/S (Tangage) aurait du être sorti plutôt que rentré :

Et voici les données de l’IHM ESPHome :

à première vue, tes valeurs semblent correctes et cohérentes avec la position des panneaux.

Si sur le tangage, les panneaux s’asservissent dans la mauvaise direction, tu peux :

1 - inverser la polarité de ton vérin
OU
2 - inverser ton GPIO12 et GPIO13
OU
3 - inverser IN1A et IN2A
OU
4 - inverser FORWARD et REVERSE dans le script "PitchPilot"
OU
5 - inverser pin_a et pin_b dans ton "fan/Moteur A"

Les valeurs remontées par l’IMU MPU6050 sont bruitées, je t’encourage à remettre une filtrage.
Voici ma version :

- platform: mpu6050
    address: 0x68
    accel_x:
      id: accel_x
      name: "IMU Accel X"
      internal: True
      filters:
        - offset: $offset_accX
        - clamp:
            min_value: -9.81
            max_value: 9.81
        - exponential_moving_average:
            alpha: 0.20
            send_every: 2
    accel_y:
      id: accel_y
      name: "IMU Accel Y"
      internal: True
      filters:
        - offset: $offset_accY
        - clamp:
            min_value: -9.81
            max_value: 9.81
        - exponential_moving_average:
            alpha: 0.20
            send_every: 2
    accel_z:
      id: accel_z
      name: "IMU Accel z"
      internal: True
      filters:
        - multiply: -1.0
        - offset: $offset_accZ
        - timeout: 1s
        - clamp:
            min_value: 0.01 #IMU à l'envers, tombé
            max_value: 9.81
            ignore_out_of_range: False
        - exponential_moving_average:
            alpha: 0.20
            send_every: 2
    temperature:
      name: "MPU6050 Temperature"
      id: MPU_temp
      internal: True
    update_interval: $boucle_asservissement

Si tu es passé en mode manuel, c’est probablement à cause des valeurs IMU non filtrées. Si en entrée tu as des valeurs non filtrées, tu réalises des calculs non filtrées et tu peux avoir des pics, et donc des valeurs qui sortent des angle_max_*.

D’ailleurs je pense que tu as une petite coquille dans ton code, angle_min_tangage: '35.0' devrait être négatif en angle_min_tangage: '-35.0'.

J’ai modifié le code comme tu le préconises :

  - platform: mpu6050
    address: 0x68
    update_interval: 500ms

    # Description
    #   Déclaration des capteurs d'accélération du MPU6050
    # Utilisation :
    #   Ces capteurs 'accel_x', 'accel_y', 'accel_z' sont utilisés pour le calcul des
    #   angles des panneaux dans les capteurs 'PV_roulis' et 'PV_tangage'
    accel_x:
      id: accel_x
      name: "MPU Accel X"
      filters:
        - offset: $offset_accX
        - clamp:
            min_value: -9.81
            max_value: 9.81
        - exponential_moving_average:
            alpha: 0.20
            send_every: 2
    accel_y:
      id: accel_y
      name: "MPU Accel Y"
      filters:
        - offset: $offset_accY
        - clamp:
            min_value: -9.81
            max_value: 9.81
        - exponential_moving_average:
            alpha: 0.20
            send_every: 2
    accel_z:
      id: accel_z
      name: "MPU Accel Z"
      filters:
        - multiply: -1.0
        - offset: $offset_accZ
        - timeout: 1s
        - clamp:
            min_value: 0.01                 # IMU à l'envers, tombé
            max_value: 9.81
            ignore_out_of_range: false
        - exponential_moving_average:
            alpha: 0.20
            send_every: 2

  # Description
  #   Déclaration du capteur de température du MPU6050
  # Utilisation :
  #   Ce capteur est utilisé pour remonter la température à HA par l'intermédiaire
  #   du capteur 'MPU température'
    temperature:
      id: MPU_temp
      name: "solar-tracker Temperature"
      filters:
       - sliding_window_moving_average:
          window_size: 10
          send_every: 5

Et comme le tangage partait toujours à l’opposé, j’ai modifier le code du script en inversant le FORWARD / REVERSE :

  - id: PitchPilot
    mode: single
    parameters:
      offset: float
    then:
      - lambda: |-
          if (abs(offset)>$precision_offset) {
            int speed = 0;
            if(abs(offset)>$max_speed_offset) {
              speed = 100;
            }
            else {
              speed = ${vitesse_mini_verins} + (40*abs(offset)/$max_speed_offset);
            }
            if (offset>0) {
              auto call = id(tangage_verin).turn_on();
              call.set_speed(speed);
              call.set_direction(FanDirection::REVERSE);
              call.perform();
            } else {
              auto call = id(tangage_verin).turn_on();
              call.set_speed(speed);
              call.set_direction(FanDirection::FORWARD);
              call.perform();
            }
          }
          else {
            auto call = id(tangage_verin).turn_off();
            call.perform();
          }

Ça semble mieux fonctionner. Mais il passe quand même en mode manuel malgré changement des butées :

  angle_min_roulis: '-60.0'       # Butée physique de l'angle minimum en degré que peut atteindre le roulis
  angle_max_roulis: '60.0'        # Butée physique de l'angle maximum en degré que peut atteindre le roulis
  angle_min_tangage: '-25.0'      # Butée physique de l'angle minimum en degré que peut atteindre le tangage
  angle_max_tangage: '-35.0'      # Butée physique de l'angle maximum en degré que peut atteindre le tangage

J’ai voulu faire le test de mise en position “storm”, et il n’est pas à plat, même si j’ai indiqué :

  repos_tangage: '-0.0'           # angle tangage repos mode Nuit/Tempête par rapport à l'horizontal
  repos_roulis: '-0.0'            # angle roulis repos mode Nuit/Tempête par rapport à l'horizontal

Il vaut mieux toucher au offset_tangage et offset_roulis ?

C’est normal qu’il ne passe pas à plat, car tu as mis

angle_min_tangage: '-25.0'      # Butée physique de l'angle minimum en degré que peut atteindre le tangage
angle_max_tangage: '-35.0'      # Butée physique de l'angle maximum en degré que peut atteindre le tangage

Il te faut une valeur positive à angle_max_tangage. Sinon là, il va rester entre -25 et -35.

J’avais introduis ces 4 paramètres, car mes vérins permettaient un débattement plus important que ce que ma structure peut réaliser. Grosso modo, mes vérins ne s’arrêtent pas quand je suis en butée max.
Donc j’ai une première limitation de la course des vérins, sur les entités sunRoulis et sunTangage.

Dans sunRoulis/filters/clamp et sunTangage/filters/clamp, je contrains les valeurs à rester dans la plage [-52; 52] et [-50; 30]. C’est le domaine utile d’asservissement des panneaux.

Mais comme mes vérins peuvent aller plus loin que ça, et je ne le souhaite pas, si j’ai un problème, quelque soit la raison, et que je détecte une position qui sort de ces 2 plages, alors je coupe tout et je passe en mode manuel. Il faut que angle_max_tangage, angle_min_tangage et pareil sur roulis, soient plus grand que le réalisable de ton tracker, sinon tu vas sans cesse passer en mode manuel quand tu arriveras aux limites.

- platform: template
    id: sunRoulis
    name: sunRoulis
    unit_of_measurement: °
    internal: False
    update_interval: 10.1s
    lambda: |-
      if (id(storm_mode).state) return {$repos_roulis}; // Angle azimuth repos
      return -(-acos(id(sunY).state/sqrt( pow( id(sunY).state , 2) + pow( id(sunZ).state , 2)))*180/$PI+90);
    filters: 
      - clamp:
          min_value: -52
          max_value: 52
          ignore_out_of_range: False

  - platform: template
    id: sunTangage
    name: sunTangage
    unit_of_measurement: °
    internal: False
    update_interval: 10.15s
    lambda: |-
      if (id(storm_mode).state) return {$repos_tangage}; // Angle elevation repos
      return asin(id(sunX).state)/sqrt( pow( id(sunX).state , 2) + pow( id(sunZ).state , 2))*180/$PI;
    filters: 
      - clamp:
          min_value: -50
          max_value: 30
          ignore_out_of_range: False

Mes variables sont sans doute mal nommées.

Si je renomme les variables, elles deviendrait ainsi :

l’actuel angle_min_tangage –> à renommer en seuil_min_tangage_manuel
l’actuel angle_max_tangage –> à renommer en seuil_max_tangage_manuel
l’actuel angle_min_roulis –> à renommer en seuil_min_roulis_manuel
l’actuel angle_max_roulis –> à renommer en seuil_max_roulis_manuel
-52 –> angle_min_tangage
52 –> angle_max_tangage
-50 –> angle_min_roulis
30 –> angle_max_roulis

Si je ne suis pas clair, n’hésite pas.

@Scorpix , merci pour ton aide, mon traqueur arrive désormais à suivre le soleil.

Il faudrait que j’optimise un peu sa position, pour ça j’ai ajouté des bagues sur les fixation des vérins pour limiter les jeux, et je vais réduire le cône de suivi du soleil precision_offset, je l’avais passé à 10° pour limiter les actions sur les vérins, je vais essayer de le repasser à 2° comme toi …

Par contre, le panneau n’est pas à l’horizontale en position storm qui, pour moi est normalement à 0° de tangage et 0° sur le roulis.
Comment faire pour corriger cela ?
Est-ce que ça va entrainer une correction aussi sur le suivi soleil, si je touche à offset_tangage et offset_roulis ?