← Algoritmo de seguidor solar con PyEphem en un Raspberry PLC
Seguidores solares de dos ejesRaspberry PLC 21CANopenControl
Algoritmo de seguidor solar con PyEphem en un Raspberry PLC — ejemplo completo
Calcula elevación y azimut solar con PyEphem y gobierna un seguidor de dos ejes desde un Raspberry PLC 21. Código Python con posición de reposo nocturna.
Programa completo y ejecutable para el Raspberry PLC 21 (solar-tracking-pyephem.py): incluye cabecera de conexionado, requisitos y notas de integración.
Descarga el pack completo del proyecto — gratisEste ejemplo + los relacionados + lista de materiales
Vista de solo lectura.
#!/usr/bin/env python3
# -----------------------------------------------------------------------------
# COMPLETE EXAMPLE — Astronomical solar tracking algorithm with PyEphem
#
# Device: Raspberry PLC 21 (Industrial Shields)
# Based on: dual-axis solar tracker project
#
# Requirements:
# pip3 install ephem
#
# Logic:
# A PyEphem observer configured with lat/long/altitude computes the sun's
# elevation and azimuth at any instant. The main loop updates the setpoint
# of both axes every 300 s. When the sun drops below the minimum elevation
# threshold, the tracker goes to the night rest position and waits; at
# sunrise it re-arms automatically and resumes tracking.
#
# The move_*_axis() functions are stubs: on the real tracker they drive the
# motor via the CANopen VFD until the encoder confirms the target position
# (see lovato-vlb3-vfd-canopen-sdo.py and canopen-encoder-inclinometer-reading.py).
# -----------------------------------------------------------------------------
import math
import time
from datetime import datetime, timezone
import ephem
# --- Installation site (adjust per plant) -------------------------------------
LATITUDE = '41.6167' # decimal degrees, as a string for ephem
LONGITUDE = '1.8333'
ALTITUDE_M = 280 # meters above sea level
# --- Tracking parameters ------------------------------------------------------
PERIOD_S = 300 # setpoint update every 300 s
MIN_ELEV_DEG = 5.0 # below this elevation -> night rest position
REST_POS_ELEV = 0.0 # degrees, table horizontal
REST_POS_AZ = 90.0 # degrees, facing east (ready for sunrise)
# --- Mechanical axis limits (software limit switches) --------------------------
ELEV_MIN, ELEV_MAX = 0.0, 75.0
AZ_MIN, AZ_MAX = 60.0, 300.0
# --- Astronomical observer -----------------------------------------------------
obs = ephem.Observer()
obs.lat = LATITUDE
obs.lon = LONGITUDE
obs.elevation = ALTITUDE_M
sun = ephem.Sun()
def get_sun_angle(t):
"""Sun elevation (degrees) at instant t (UTC)."""
obs.date = t.strftime('%Y/%m/%d %H:%M:%S')
sun.compute(obs)
return math.degrees(float(sun.alt))
def get_azimuth_angle(t):
"""Sun azimuth (degrees, 0=N, 90=E) at instant t (UTC)."""
obs.date = t.strftime('%Y/%m/%d %H:%M:%S')
sun.compute(obs)
return math.degrees(float(sun.az))
def clamp(value, vmin, vmax):
"""Clips the setpoint to the mechanical limits of the axis."""
return max(vmin, min(vmax, value))
def move_elevation_axis(degrees):
"""Stub: move the elevation axis to 'degrees' (VFD + encoder)."""
print(f" -> ELEVATION axis to {degrees:6.2f} deg")
def move_azimuth_axis(degrees):
"""Stub: move the azimuth axis to 'degrees' (VFD + encoder)."""
print(f" -> AZIMUTH axis to {degrees:6.2f} deg")
def go_to_rest():
"""Night position: flat table facing east."""
print("Sun below the horizon: night rest position")
move_elevation_axis(REST_POS_ELEV)
move_azimuth_axis(REST_POS_AZ)
def tracking_loop():
at_rest = False
while True:
now = datetime.now(timezone.utc)
elev = get_sun_angle(now)
az = get_azimuth_angle(now)
print(f"{now:%H:%M:%S} UTC sun: elev={elev:6.2f} az={az:6.2f}")
if elev < MIN_ELEV_DEG:
# Night or twilight: a single rest maneuver, then wait.
if not at_rest:
go_to_rest()
at_rest = True
else:
# Daytime: automatic re-arm at sunrise and normal tracking.
if at_rest:
print("Sunrise detected: re-arming tracking")
at_rest = False
move_elevation_axis(clamp(elev, ELEV_MIN, ELEV_MAX))
move_azimuth_axis(clamp(az, AZ_MIN, AZ_MAX))
time.sleep(PERIOD_S)
if __name__ == '__main__':
try:
tracking_loop()
except KeyboardInterrupt:
print("\nManual stop: the tracker stays at its last position")
Descarga el pack completo del proyecto — gratisEste ejemplo + los relacionados + lista de materiales