Ir al contenido

← 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