← Lectura de encoders CANopen en un seguidor solar con PLC
Seguidores solares de dos ejesRaspberry PLC 21CANopenAdquisición
Lectura de encoders CANopen en un seguidor solar con PLC — ejemplo completo
Lee encoders e inclinómetros CANopen desde un Raspberry PLC 21 en Python. Estado NMT OPERATIONAL, lecturas SDO de position_value y calibración a grados.
Programa completo y ejecutable para el Raspberry PLC 21 (canopen-encoder-inclinometer-reading.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 — Reading CANopen inclinometers/encoders (TY7953)
#
# Device: Raspberry PLC 21 (Industrial Shields), built-in CAN bus (can0)
# Based on: dual-axis solar tracker project
#
# CAN bus / requirements:
# sudo ip link set can0 up type can bitrate 125000
# pip3 install canopen
# EDS file of the TY7953 encoder in the same directory (TY7953.eds)
#
# Logic:
# Two TY7953 encoders/inclinometers share the bus with the VFD:
# node 4 measures the table elevation and node 5 the azimuth. After
# switching each node to NMT OPERATIONAL state, the position is read via
# the "position_value" SDO. The raw value is converted to degrees using
# the plant calibration: 10 units per degree, plus a mechanical zero
# offset per axis.
# -----------------------------------------------------------------------------
import time
import canopen
CAN_CHANNEL = 'can0'
CAN_BITRATE = 125000
EDS_ENCODER = 'TY7953.eds'
NODE_ELEVATION = 4 # elevation axis encoder
NODE_AZIMUTH = 5 # azimuth axis encoder
# --- Calibration (adjusted during commissioning of each tracker) --------------
UNITS_PER_DEGREE = 10.0 # 10 u/deg
OFFSET_ELEV = 0 # raw reading with the table horizontal
OFFSET_AZ = 0 # raw reading with the table facing south
def connect_encoder(network, node_id):
"""Registers an encoder on the bus and switches it to OPERATIONAL."""
encoder = network.add_node(node_id, EDS_ENCODER)
encoder.nmt.state = 'OPERATIONAL'
# Short wait so the node processes the NMT state change.
time.sleep(0.1)
print(f"Encoder node {node_id}: state {encoder.nmt.state}")
return encoder
def read_raw_position(encoder):
"""Reads the position_value object from the encoder dictionary via SDO."""
return encoder.sdo["position_value"].raw
def raw_to_degrees(raw, offset):
"""Converts encoder units to degrees using the plant calibration."""
return (raw - offset) / UNITS_PER_DEGREE
def main():
network = canopen.Network()
network.connect(channel=CAN_CHANNEL, bustype='socketcan',
bitrate=CAN_BITRATE)
try:
enc_elev = connect_encoder(network, NODE_ELEVATION)
enc_az = connect_encoder(network, NODE_AZIMUTH)
print("Reading positions (Ctrl+C to exit)")
while True:
raw_e = read_raw_position(enc_elev)
raw_a = read_raw_position(enc_az)
elev_deg = raw_to_degrees(raw_e, OFFSET_ELEV)
az_deg = raw_to_degrees(raw_a, OFFSET_AZ)
print(f"elevation: {raw_e:6d} u -> {elev_deg:7.2f} deg "
f"azimuth: {raw_a:6d} u -> {az_deg:7.2f} deg")
time.sleep(1)
except KeyboardInterrupt:
print("\nReading stopped by the user")
finally:
network.disconnect()
print("CAN bus closed")
if __name__ == '__main__':
main()
Descarga el pack completo del proyecto — gratisEste ejemplo + los relacionados + lista de materiales