From 6a1183ccf5e5f3055270dce9f7c22d713f7398e2 Mon Sep 17 00:00:00 2001 From: Geens Date: Sat, 3 Aug 2024 16:28:08 +0200 Subject: [PATCH] Initial commit, missing cycle time --- .gitignore | 2 ++ main.py | 60 +++++++++++++++++++++++++++++++++++++ requirements.txt | 1 + src/__init__.py | 2 ++ src/hardware.py | 31 ++++++++++++++++++++ src/logic.py | 3 ++ uno_relay_modbus.ino | 70 ++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 169 insertions(+) create mode 100644 .gitignore create mode 100644 main.py create mode 100644 requirements.txt create mode 100644 src/__init__.py create mode 100644 src/hardware.py create mode 100644 src/logic.py create mode 100644 uno_relay_modbus.ino diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3040d64 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +__pycache__/ +.vscode/ \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..a9b31a3 --- /dev/null +++ b/main.py @@ -0,0 +1,60 @@ +import minimalmodbus +import time +import traceback +import argparse +import serial.tools.list_ports +from src.hardware import Hardware +from src.logic import loop + +def get_first_available_com_port(): + ports = list(serial.tools.list_ports.comports()) + return ports[0].device if ports else 'COM3' + +def main(): + parser = argparse.ArgumentParser(description='UNO Relay Modbus Controller') + parser.add_argument('--com_port', type=str, default=get_first_available_com_port(), + help='COM port for the Modbus connection') + parser.add_argument('--slave_id', type=int, default=1, + help='Slave ID for the Modbus device') + parser.add_argument('--cycle_time', type=float, default=0.01, + help='Cycle time in seconds for the main loop') + args = parser.parse_args() + + com_port = args.com_port + slave_id = args.slave_id + cycle_time = args.cycle_time + + while True: + try: + instrument = minimalmodbus.Instrument(com_port, slave_id) + instrument.serial.baudrate = 9600 + instrument.serial.bytesize = 8 + instrument.serial.parity = minimalmodbus.serial.PARITY_NONE + instrument.serial.stopbits = 1 + instrument.serial.timeout = 1 + time.sleep(3) + hardware = Hardware(instrument) + + while True: + start_time = time.time() + + hardware.update() + loop(hardware) + + execution_time = time.time() - start_time + if execution_time > cycle_time: + print(f"Warning: Loop execution time ({execution_time:.4f}s) exceeded cycle time ({cycle_time:.4f}s)") + + sleep_time = max(0, cycle_time - execution_time) + time.sleep(sleep_time) + + except KeyboardInterrupt: + print("Stopped by user") + break + except Exception as e: + print(f"Error: {e}") + print(traceback.format_exc()) + time.sleep(5) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..3897fc5 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +minimalmodbus==1.0.2 \ No newline at end of file diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 0000000..6d32adb --- /dev/null +++ b/src/__init__.py @@ -0,0 +1,2 @@ +from .hardware import Hardware +from .logic import loop \ No newline at end of file diff --git a/src/hardware.py b/src/hardware.py new file mode 100644 index 0000000..e9f4de8 --- /dev/null +++ b/src/hardware.py @@ -0,0 +1,31 @@ +import minimalmodbus + +class Hardware: + def __init__(self, instrument): + self.instrument = instrument + self.relay_0_address = 0 + self.relay_1_address = 1 + self.button_0_address = 0 + self.button_1_address = 1 + self.relay_0 = False + self.relay_1 = False + self.button_0 = False + self.button_1 = False + + def update(self): + self.instrument.write_bit(self.relay_0_address, self.relay_0, functioncode=5) + self.instrument.write_bit(self.relay_1_address, self.relay_1, functioncode=5) + self.button_0 = self.instrument.read_bit(self.button_0_address, functioncode=2) + self.button_1 = self.instrument.read_bit(self.button_1_address, functioncode=2) + + def set_relay_0(self, value): + self.relay_0 = value + + def set_relay_1(self, value): + self.relay_1 = value + + def get_button_0(self): + return self.button_0 + + def get_button_1(self): + return self.button_1 \ No newline at end of file diff --git a/src/logic.py b/src/logic.py new file mode 100644 index 0000000..56039d9 --- /dev/null +++ b/src/logic.py @@ -0,0 +1,3 @@ +def loop(hardware): + hardware.set_relay_0(hardware.get_button_0() != hardware.get_button_1()) + hardware.set_relay_1(hardware.get_button_0() and hardware.get_button_1()) \ No newline at end of file diff --git a/uno_relay_modbus.ino b/uno_relay_modbus.ino new file mode 100644 index 0000000..3e8c34e --- /dev/null +++ b/uno_relay_modbus.ino @@ -0,0 +1,70 @@ +#include + +#define BAUD_RATE 9600 +#define SLAVE_ID 1 +#define COIL_COUNT 4 +#define COIL_START 1 + +#define COIL_0 4 +#define COIL_1 5 +#define COIL_2 6 +#define COIL_3 7 + +#define STATUS_0 12 +#define STATUS_1 11 + +ModbusSerial mb (Serial, SLAVE_ID); + +void setup() { + Serial.begin (BAUD_RATE); + while (! Serial); + mb.config(BAUD_RATE); + + mb.addCoil (0); + mb.addCoil (1); + mb.addCoil (2); + mb.addCoil (3); + + mb.addIsts(0); + mb.addIsts(1); + + pinMode(COIL_0, OUTPUT); + pinMode(COIL_1, OUTPUT); + pinMode(COIL_2, OUTPUT); + pinMode(COIL_3, OUTPUT); + + pinMode(STATUS_0, INPUT_PULLUP); + pinMode(STATUS_1, INPUT_PULLUP); +} + +void loop() { + mb.task(); + readCoilValues(); + writeStatusValues(); +} + +void readCoilValues() { + digitalWrite(COIL_0, mb.coil(0)); + digitalWrite(COIL_1, mb.coil(1)); + digitalWrite(COIL_2, mb.coil(2)); + digitalWrite(COIL_3, mb.coil(3)); +} + +void writeStatusValues() { + mb.setIsts(0, !digitalRead(STATUS_0)); + mb.setIsts(1, !digitalRead(STATUS_1)); +} + + + + + + + + + + + + + +