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
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
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.:
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.
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
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 ?
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é :
à 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 :
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'.
- 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
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.
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
@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 ?