mirror of
https://github.com/naruxde/revpimodio2.git
synced 2026-03-31 15:08:09 +02:00
docs: Update documentation for improved clarity and consistency
Revised various sections across multiple documentation files to reflect updated methods (`run_plc` replacing manual setup with `cycleloop`) and adjust for new default parameters (e.g., `autorefresh`). Enhanced descriptions for timers, Cycletools usage, and new method explanations. Removed outdated or redundant examples and updated system requirements. Signed-off-by: Sven Sager <akira@narux.de>
This commit is contained in:
@@ -36,7 +36,6 @@ Gateway modules provide generic IOs (like ``Input_1``, ``Output_1``, etc.) that
|
||||
rpi.io.Input_1.replace_io(
|
||||
"temperature", # New IO name
|
||||
"h", # struct format: signed short
|
||||
defaultvalue=0 # Default value
|
||||
)
|
||||
|
||||
# Use the custom IO by its new name
|
||||
@@ -70,6 +69,7 @@ Common format codes for ``replace_io`` (see `Python struct format characters <ht
|
||||
* ``'i'`` - signed int (-2147483648 to 2147483647)
|
||||
* ``'I'`` - unsigned int (0 to 4294967295)
|
||||
* ``'f'`` - float (32-bit)
|
||||
* ``'d'`` - float (64-bit)
|
||||
|
||||
Multiple Custom IOs
|
||||
-------------------
|
||||
@@ -82,8 +82,8 @@ Define multiple custom IOs programmatically by replacing generic gateway IOs:
|
||||
|
||||
# Replace multiple gateway IOs with custom definitions
|
||||
# Assuming a gateway module with Input_1, Input_2, Output_1, Output_2
|
||||
rpi.io.Input_1.replace_io("temperature", "h", defaultvalue=0)
|
||||
rpi.io.Input_2.replace_io("humidity", "h", defaultvalue=0)
|
||||
rpi.io.Input_1.replace_io("temperature", "h")
|
||||
rpi.io.Input_2.replace_io("humidity", "h")
|
||||
rpi.io.Output_1.replace_io("setpoint", "h", defaultvalue=700)
|
||||
rpi.io.Output_2.replace_io("control_word", "H", defaultvalue=0)
|
||||
|
||||
@@ -126,12 +126,10 @@ Create an INI-style configuration file (``replace_ios.conf``):
|
||||
[temperature]
|
||||
replace = Input_1
|
||||
frm = h
|
||||
defaultvalue = 0
|
||||
|
||||
[humidity]
|
||||
replace = Input_2
|
||||
frm = h
|
||||
defaultvalue = 0
|
||||
|
||||
[setpoint]
|
||||
replace = Output_1
|
||||
@@ -181,7 +179,9 @@ This is useful for:
|
||||
Watchdog Management
|
||||
===================
|
||||
|
||||
The hardware watchdog monitors your program and resets the system if it stops responding.
|
||||
The hardware watchdog monitors your program and resets the system if it stops responding. If you
|
||||
use the software watchdog will will only works if you use RevPiPyControl as runtime for your python
|
||||
program.
|
||||
|
||||
How the Watchdog Works
|
||||
-----------------------
|
||||
@@ -197,8 +197,6 @@ Cyclic Watchdog Toggle
|
||||
|
||||
import revpimodio2
|
||||
|
||||
rpi = revpimodio2.RevPiModIO(autorefresh=True)
|
||||
|
||||
def main_cycle(ct):
|
||||
# Toggle every 10 cycles (200ms @ 20ms)
|
||||
if ct.flank10c:
|
||||
@@ -207,7 +205,7 @@ Cyclic Watchdog Toggle
|
||||
# Your control logic
|
||||
ct.io.output.value = ct.io.input.value
|
||||
|
||||
rpi.cycleloop(main_cycle)
|
||||
revpimodio2.run_plc(main_cycle)
|
||||
|
||||
Event-Driven Watchdog Toggle
|
||||
-----------------------------
|
||||
@@ -234,134 +232,6 @@ Event-Driven Watchdog Toggle
|
||||
rpi.handlesignalend()
|
||||
rpi.mainloop()
|
||||
|
||||
Conditional Watchdog
|
||||
--------------------
|
||||
|
||||
Enable watchdog only when system is operational:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def machine_with_watchdog(ct):
|
||||
if ct.first:
|
||||
ct.var.state = "IDLE"
|
||||
ct.var.watchdog_enabled = False
|
||||
|
||||
# Enable watchdog only in RUNNING state
|
||||
if ct.var.state == "RUNNING":
|
||||
if not ct.var.watchdog_enabled:
|
||||
ct.var.watchdog_enabled = True
|
||||
print("Watchdog enabled")
|
||||
|
||||
# Toggle watchdog
|
||||
if ct.flank10c:
|
||||
ct.core.wd_toggle()
|
||||
|
||||
else:
|
||||
ct.var.watchdog_enabled = False
|
||||
|
||||
# State machine logic
|
||||
if ct.var.state == "IDLE":
|
||||
if ct.io.start_button.value:
|
||||
ct.var.state = "RUNNING"
|
||||
|
||||
elif ct.var.state == "RUNNING":
|
||||
ct.io.motor.value = True
|
||||
if ct.io.stop_button.value:
|
||||
ct.var.state = "IDLE"
|
||||
|
||||
rpi = revpimodio2.RevPiModIO(autorefresh=True)
|
||||
rpi.cycleloop(machine_with_watchdog)
|
||||
|
||||
Combining Paradigms
|
||||
===================
|
||||
|
||||
Combine cyclic and event-driven programming for optimal results.
|
||||
|
||||
Cyclic Control with Event UI
|
||||
-----------------------------
|
||||
|
||||
Use cyclic for time-critical control, events for user interface:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import revpimodio2
|
||||
import threading
|
||||
|
||||
rpi = revpimodio2.RevPiModIO(autorefresh=True)
|
||||
|
||||
def cyclic_control(ct: revpimodio2.Cycletools):
|
||||
"""Fast control loop."""
|
||||
if ct.first:
|
||||
ct.var.setpoint = 50.0
|
||||
ct.var.running = False
|
||||
|
||||
if ct.var.running:
|
||||
# Fast control logic
|
||||
error = ct.var.setpoint - ct.io.sensor.value
|
||||
if error > 5:
|
||||
ct.io.actuator.value = True
|
||||
elif error < -5:
|
||||
ct.io.actuator.value = False
|
||||
|
||||
def on_setpoint_change(ioname, iovalue):
|
||||
"""Event handler for user setpoint changes."""
|
||||
print(f"New setpoint: {iovalue}")
|
||||
# Access ct.var from event requires thread-safe approach
|
||||
# In practice, use shared data structure or message queue
|
||||
|
||||
def on_start(ioname, iovalue):
|
||||
print("System started")
|
||||
|
||||
def on_stop(ioname, iovalue):
|
||||
print("System stopped")
|
||||
|
||||
# Register user events
|
||||
rpi.io.start_button.reg_event(on_start, edge=revpimodio2.RISING)
|
||||
rpi.io.stop_button.reg_event(on_stop, edge=revpimodio2.RISING)
|
||||
rpi.io.setpoint_input.reg_event(on_setpoint_change, delay=100)
|
||||
|
||||
# Run cyclic loop in background
|
||||
threading.Thread(
|
||||
target=lambda: rpi.cycleloop(cyclic_control),
|
||||
daemon=True
|
||||
).start()
|
||||
|
||||
# Run event loop in main thread
|
||||
rpi.handlesignalend()
|
||||
rpi.mainloop()
|
||||
|
||||
Event Triggers with Cyclic Processing
|
||||
--------------------------------------
|
||||
|
||||
Use events to trigger actions, cyclic for processing:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import revpimodio2
|
||||
|
||||
rpi = revpimodio2.RevPiModIO(autorefresh=True)
|
||||
|
||||
def cyclic_processor(ct):
|
||||
"""Process work queue."""
|
||||
if ct.first:
|
||||
ct.var.work_queue = []
|
||||
|
||||
# Process queued work
|
||||
if ct.var.work_queue:
|
||||
item = ct.var.work_queue.pop(0)
|
||||
process_item(item)
|
||||
|
||||
def on_new_item(ioname, iovalue):
|
||||
"""Queue work from events."""
|
||||
# Note: Accessing ct.var from events requires synchronization
|
||||
# This is a simplified example
|
||||
print(f"New item queued from {ioname}")
|
||||
|
||||
rpi.io.trigger1.reg_event(on_new_item, edge=revpimodio2.RISING)
|
||||
rpi.io.trigger2.reg_event(on_new_item, edge=revpimodio2.RISING)
|
||||
|
||||
rpi.cycleloop(cyclic_processor)
|
||||
|
||||
Performance Optimization
|
||||
========================
|
||||
|
||||
@@ -487,23 +357,19 @@ Track and handle I/O errors:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
rpi = revpimodio2.RevPiModIO(autorefresh=True)
|
||||
rpi.maxioerrors = 10 # Exception after 10 errors
|
||||
maxioerrors = 10 # Exception after 10 errors
|
||||
|
||||
def main_cycle(ct):
|
||||
# Check error count periodically
|
||||
if ct.flank20c:
|
||||
if rpi.ioerrors > 5:
|
||||
print(f"Warning: {rpi.ioerrors} I/O errors detected")
|
||||
if rpi.core.ioerrorcount > maxioerrors:
|
||||
print(f"Warning: {rpi.core.ioerrorcount} I/O errors detected")
|
||||
ct.io.warning_led.value = True
|
||||
|
||||
# Normal logic
|
||||
ct.io.output.value = ct.io.input.value
|
||||
|
||||
try:
|
||||
rpi.cycleloop(main_cycle)
|
||||
except RuntimeError as e:
|
||||
print(f"I/O error threshold exceeded: {e}")
|
||||
revpimodio2.run_plc(main_cycle)
|
||||
|
||||
Best Practices
|
||||
==============
|
||||
@@ -600,35 +466,6 @@ Document complex logic:
|
||||
# State machine implementation
|
||||
# ...
|
||||
|
||||
Testing
|
||||
-------
|
||||
|
||||
Test your code thoroughly:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def test_temperature_control(ct):
|
||||
"""Test temperature control logic."""
|
||||
|
||||
if ct.first:
|
||||
ct.var.cooling_active = False
|
||||
ct.var.test_temp = 20.0
|
||||
|
||||
# Simulate temperature increase
|
||||
if ct.var.test_temp < 80:
|
||||
ct.var.test_temp += 0.5
|
||||
|
||||
# Test control logic
|
||||
temp = ct.var.test_temp
|
||||
|
||||
if temp > 75 and not ct.var.cooling_active:
|
||||
assert ct.io.cooling.value == True
|
||||
ct.var.cooling_active = True
|
||||
|
||||
if temp < 65 and ct.var.cooling_active:
|
||||
assert ct.io.cooling.value == False
|
||||
ct.var.cooling_active = False
|
||||
|
||||
Logging
|
||||
-------
|
||||
|
||||
@@ -676,6 +513,7 @@ Always validate external inputs:
|
||||
"""Validate setpoint range."""
|
||||
if 0 <= iovalue <= 100:
|
||||
rpi.io.setpoint.value = iovalue
|
||||
rpi.io.error_led.value = False
|
||||
else:
|
||||
print(f"Invalid setpoint: {iovalue}")
|
||||
rpi.io.error_led.value = True
|
||||
|
||||
@@ -78,10 +78,11 @@ Adjust cycle time to match your needs:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
rpi = revpimodio2.RevPiModIO(autorefresh=True)
|
||||
rpi = revpimodio2.RevPiModIO()
|
||||
rpi.cycletime = 100 # Set to 100ms
|
||||
rpi.autorefresh_all()
|
||||
|
||||
**Important:** Faster cycle times consume more CPU. Choose the slowest cycle time that meets your requirements.
|
||||
**Important:** Faster cycle times consume more CPU. Choose the slowest cycle time that meets your requirements. Default values will fit most needs.
|
||||
|
||||
Error Handling
|
||||
--------------
|
||||
@@ -90,10 +91,10 @@ Configure I/O error threshold:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
rpi.maxioerrors = 10 # Raise exception after 10 errors
|
||||
maxioerrors = 10 # Raise exception after 10 errors
|
||||
|
||||
# Check error count
|
||||
if rpi.ioerrors > 5:
|
||||
if rpi.core.ioerrorcount > maxioerrors:
|
||||
print("Warning: I/O errors detected")
|
||||
|
||||
Core Objects
|
||||
|
||||
@@ -42,8 +42,6 @@ Simple Cycle Loop
|
||||
|
||||
import revpimodio2
|
||||
|
||||
rpi = revpimodio2.RevPiModIO(autorefresh=True)
|
||||
|
||||
def main_cycle(ct: revpimodio2.Cycletools):
|
||||
"""Execute each cycle."""
|
||||
if ct.io.start_button.value:
|
||||
@@ -51,10 +49,17 @@ Simple Cycle Loop
|
||||
if ct.io.stop_button.value:
|
||||
ct.io.motor.value = False
|
||||
|
||||
rpi.cycleloop(main_cycle)
|
||||
revpimodio2.run_plc(main_cycle)
|
||||
|
||||
# .run_plc is a shortcut for:
|
||||
# rpi = revpimodio2.RevPiModIO(autorefresh=True)
|
||||
# rpi.handlesignalend()
|
||||
# rpi.cycleloop(main_cycle)
|
||||
|
||||
The ``main_cycle`` function is called repeatedly at the configured cycle time (typically 20-50ms).
|
||||
|
||||
**Info:** ``rpi.handlesignalend()``
|
||||
|
||||
Understanding Cycle Time
|
||||
-------------------------
|
||||
|
||||
@@ -68,10 +73,9 @@ Adjust cycle time to match your needs:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
rpi = revpimodio2.RevPiModIO(autorefresh=True)
|
||||
rpi.cycletime = 100 # 100ms = 10 Hz
|
||||
revpimodio2.run_plc(main_cycle, cycletime=100) # 100ms = 10 Hz
|
||||
|
||||
**Important:** Faster cycle times consume more CPU. Choose the slowest cycle time that meets your requirements.
|
||||
**Important:** Faster cycle times consume more CPU but will detect fast changes of input values.
|
||||
|
||||
Cycletools Object
|
||||
=================
|
||||
@@ -109,8 +113,7 @@ Use ``ct.first`` and ``ct.last`` for setup and teardown:
|
||||
ct.io.motor.value = False
|
||||
print(f"Total cycles: {ct.var.counter}")
|
||||
|
||||
rpi = revpimodio2.RevPiModIO(autorefresh=True)
|
||||
rpi.cycleloop(main_cycle)
|
||||
revpimodio2.run_plc(main_cycle)
|
||||
|
||||
Persistent Variables
|
||||
====================
|
||||
@@ -155,6 +158,7 @@ Detect input changes efficiently without storing previous values:
|
||||
print("Button released!")
|
||||
|
||||
rpi = revpimodio2.RevPiModIO(autorefresh=True)
|
||||
rpi.handlesignalend()
|
||||
rpi.cycleloop(main_cycle)
|
||||
|
||||
Edge types:
|
||||
@@ -176,17 +180,16 @@ Toggle flags alternate between True/False at regular intervals:
|
||||
.. code-block:: python
|
||||
|
||||
def main_cycle(ct):
|
||||
# Blink LED - flag5c alternates every 5 cycles
|
||||
ct.io.blink_led.value = ct.flag5c
|
||||
# Blink LED - flag5c alternates every cycle
|
||||
ct.io.blink_led.value = ct.flag1c
|
||||
|
||||
# Different blink rates
|
||||
ct.io.fast_blink.value = ct.flag2c # Every 2 cycles
|
||||
ct.io.fast_blink.value = ct.flag5c # Every 5 cycles
|
||||
ct.io.slow_blink.value = ct.flag20c # Every 20 cycles
|
||||
|
||||
**Available toggle flags:**
|
||||
|
||||
* ``ct.flag1c`` - Every cycle
|
||||
* ``ct.flag2c`` - Every 2 cycles
|
||||
* ``ct.flag5c`` - Every 5 cycles
|
||||
* ``ct.flag10c`` - Every 10 cycles
|
||||
* ``ct.flag20c`` - Every 20 cycles
|
||||
@@ -218,12 +221,12 @@ Flank flags are True for exactly one cycle at regular intervals:
|
||||
Timers
|
||||
======
|
||||
|
||||
RevPiModIO provides three timer types based on PLC standards. All timers are specified in cycle counts.
|
||||
RevPiModIO provides three timer types based on PLC standards. All timers are specified in cycle counts or milliseconds.
|
||||
|
||||
On-Delay Timer (TON/TONC)
|
||||
--------------------------
|
||||
|
||||
Output becomes True only after input is continuously True for specified cycles:
|
||||
Output becomes True only after input is continuously True for specified cycles (use ton with milliseconds value instead of cycles):
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -253,7 +256,7 @@ Output becomes True only after input is continuously True for specified cycles:
|
||||
Off-Delay Timer (TOF/TOFC)
|
||||
---------------------------
|
||||
|
||||
Output stays True for specified cycles after input goes False:
|
||||
Output stays True for specified cycles or milliseconds after input goes False (use tof with milliseconds value instead of cycles):
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -280,7 +283,7 @@ Output stays True for specified cycles after input goes False:
|
||||
Pulse Timer (TP/TPC)
|
||||
--------------------
|
||||
|
||||
Generates a one-shot pulse of specified duration:
|
||||
Generates a one-shot pulse of specified duration (use tp with milliseconds value instead of cycles):
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -305,25 +308,6 @@ Generates a one-shot pulse of specified duration:
|
||||
* Acknowledgment pulses
|
||||
* Retriggerable delays
|
||||
|
||||
Converting Time to Cycles
|
||||
--------------------------
|
||||
|
||||
Calculate cycles from desired time:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# At 20ms cycle time:
|
||||
# 1 second = 50 cycles
|
||||
# 100ms = 5 cycles
|
||||
# 2 seconds = 100 cycles
|
||||
|
||||
def main_cycle(ct):
|
||||
cycle_time_ms = rpi.cycletime
|
||||
desired_time_ms = 1500 # 1.5 seconds
|
||||
|
||||
cycles_needed = int(desired_time_ms / cycle_time_ms)
|
||||
ct.set_tonc("my_delay", cycles_needed)
|
||||
|
||||
State Machines
|
||||
==============
|
||||
|
||||
@@ -345,28 +329,29 @@ Simple State Machine
|
||||
ct.io.yellow_led.value = False
|
||||
ct.io.red_led.value = False
|
||||
|
||||
# After 100 cycles (2s @ 20ms), go to yellow
|
||||
ct.set_tonc("green_time", 100)
|
||||
if ct.get_tonc("green_time"):
|
||||
# After 2 seconds, go to yellow
|
||||
ct.set_ton("green_time", 2000)
|
||||
if ct.get_ton("green_time"):
|
||||
ct.var.state = "YELLOW"
|
||||
|
||||
elif ct.var.state == "YELLOW":
|
||||
ct.io.green_led.value = False
|
||||
ct.io.yellow_led.value = True
|
||||
|
||||
ct.set_tonc("yellow_time", 25) # 500ms
|
||||
if ct.get_tonc("yellow_time"):
|
||||
ct.set_ton("yellow_time", 500)
|
||||
if ct.get_ton("yellow_time"):
|
||||
ct.var.state = "RED"
|
||||
|
||||
elif ct.var.state == "RED":
|
||||
ct.io.yellow_led.value = False
|
||||
ct.io.red_led.value = True
|
||||
|
||||
ct.set_tonc("red_time", 150) # 3s
|
||||
if ct.get_tonc("red_time"):
|
||||
ct.set_ton("red_time", 3000)
|
||||
if ct.get_ton("red_time"):
|
||||
ct.var.state = "GREEN"
|
||||
|
||||
rpi = revpimodio2.RevPiModIO(autorefresh=True)
|
||||
rpi.handlesignalend()
|
||||
rpi.cycleloop(traffic_light)
|
||||
|
||||
Complex State Machine
|
||||
@@ -396,8 +381,8 @@ Complex State Machine
|
||||
ct.io.yellow_led.value = True
|
||||
|
||||
# 2-second startup delay
|
||||
ct.set_tonc("startup", 100)
|
||||
if ct.get_tonc("startup"):
|
||||
ct.set_ton("startup", 2000)
|
||||
if ct.get_ton("startup"):
|
||||
ct.var.state = "RUNNING"
|
||||
print("Running")
|
||||
|
||||
@@ -422,8 +407,8 @@ Complex State Machine
|
||||
# State: STOPPING - Controlled shutdown
|
||||
elif ct.var.state == "STOPPING":
|
||||
# Coast motor for 1 second
|
||||
ct.set_tofc("coast", 50)
|
||||
ct.io.motor.value = ct.get_tofc("coast")
|
||||
ct.set_tof("coast", 1000)
|
||||
ct.io.motor.value = ct.get_tof("coast")
|
||||
|
||||
if not ct.io.motor.value:
|
||||
ct.var.state = "IDLE"
|
||||
@@ -432,7 +417,7 @@ Complex State Machine
|
||||
# State: ERROR - Fault condition
|
||||
elif ct.var.state == "ERROR":
|
||||
ct.io.motor.value = False
|
||||
ct.io.red_led.value = ct.flag2c # Blink red
|
||||
ct.io.red_led.value = ct.flag5c # Blink red
|
||||
|
||||
if ct.changed(ct.io.ack_button, edge=revpimodio2.RISING):
|
||||
if not ct.io.error_sensor.value:
|
||||
@@ -442,8 +427,7 @@ Complex State Machine
|
||||
if ct.last:
|
||||
print(f"Total production: {ct.var.production_count}")
|
||||
|
||||
rpi = revpimodio2.RevPiModIO(autorefresh=True)
|
||||
rpi.cycleloop(machine_controller)
|
||||
revpimodio.run_plc(machine_controller)
|
||||
|
||||
Practical Examples
|
||||
==================
|
||||
@@ -476,14 +460,17 @@ Temperature monitoring with hysteresis control:
|
||||
|
||||
# Warning if too hot
|
||||
if temp > 85:
|
||||
ct.io.warning_led.value = ct.flag2c # Blink
|
||||
ct.core.a1green.value = False
|
||||
ct.core.a1red.value = ct.flag5c # Blink
|
||||
else:
|
||||
ct.core.a1green.value = ct.flag5c # Blink
|
||||
ct.core.a1red.value = False
|
||||
|
||||
# Emergency shutdown
|
||||
if temp > 95:
|
||||
ct.io.emergency_shutdown.value = True
|
||||
|
||||
rpi = revpimodio2.RevPiModIO(autorefresh=True)
|
||||
rpi.cycleloop(temperature_monitor)
|
||||
revpimodio2.run_plc(temperature_monitor)
|
||||
|
||||
Production Counter
|
||||
------------------
|
||||
@@ -520,8 +507,7 @@ Count production items with start/stop control:
|
||||
print(f"Final count: {ct.var.total_count}")
|
||||
ct.var.total_count = 0
|
||||
|
||||
rpi = revpimodio2.RevPiModIO(autorefresh=True)
|
||||
rpi.cycleloop(production_counter)
|
||||
revpimodio2.run_plc(production_counter)
|
||||
|
||||
Best Practices
|
||||
==============
|
||||
@@ -544,7 +530,7 @@ Minimize processing time in each cycle:
|
||||
**Guidelines:**
|
||||
|
||||
* Avoid blocking operations (network, file I/O)
|
||||
* Use flank flags for expensive operations
|
||||
* Use flank flags for expensive operations or even Threads
|
||||
* Keep cycle time ≥20ms for stability
|
||||
|
||||
Use Appropriate Cycle Time
|
||||
|
||||
@@ -94,29 +94,6 @@ Register callbacks for IO value changes:
|
||||
* ``revpimodio2.FALLING`` - True to False transition
|
||||
* ``revpimodio2.BOTH`` - Any change (default)
|
||||
|
||||
Lambda Functions
|
||||
----------------
|
||||
|
||||
Use lambda for simple callbacks:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
rpi = revpimodio2.RevPiModIO(autorefresh=True)
|
||||
|
||||
# Simple lambda callback
|
||||
rpi.io.button.reg_event(
|
||||
lambda name, val: print(f"Button: {val}")
|
||||
)
|
||||
|
||||
# Lambda with edge filter
|
||||
rpi.io.start_button.reg_event(
|
||||
lambda name, val: print("Started!"),
|
||||
edge=revpimodio2.RISING
|
||||
)
|
||||
|
||||
rpi.handlesignalend()
|
||||
rpi.mainloop()
|
||||
|
||||
Multiple Events
|
||||
---------------
|
||||
|
||||
@@ -212,12 +189,15 @@ Debouncing with Edge Detection
|
||||
Timer Events
|
||||
============
|
||||
|
||||
Execute callbacks at regular intervals independent of IO changes:
|
||||
The timer is started when the IO value changes and executes the passed
|
||||
function - even if the IO value has changed in the meantime. If the
|
||||
timer has not expired and the condition is met again, the timer is NOT
|
||||
reset to the delay value or started a second time.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def periodic_task(ioname, iovalue):
|
||||
"""Called every 500ms."""
|
||||
"""Called after 500ms."""
|
||||
print(f"Periodic task: {iovalue}")
|
||||
|
||||
rpi = revpimodio2.RevPiModIO(autorefresh=True)
|
||||
@@ -255,8 +235,8 @@ Timer Event Parameters
|
||||
|
||||
**Parameters:**
|
||||
|
||||
* ``interval`` - Milliseconds between calls
|
||||
* ``prefire`` - If True, trigger immediately on registration
|
||||
* ``interval`` - Delay in milliseconds.
|
||||
* ``prefire`` - If True, trigger immediately after starting the mainloop.
|
||||
|
||||
Threaded Events
|
||||
===============
|
||||
@@ -425,29 +405,6 @@ Sensor Logging
|
||||
rpi.handlesignalend()
|
||||
rpi.mainloop()
|
||||
|
||||
Periodic Status Report
|
||||
----------------------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import revpimodio2
|
||||
|
||||
rpi = revpimodio2.RevPiModIO(autorefresh=True)
|
||||
|
||||
def status_report(ioname, iovalue):
|
||||
"""Print system status every 10 seconds."""
|
||||
print("=== Status Report ===")
|
||||
print(f"Temperature: {rpi.core.temperature.value}°C")
|
||||
print(f"CPU Frequency: {rpi.core.frequency.value} MHz")
|
||||
print(f"IO Errors: {rpi.core.ioerrorcount.value}")
|
||||
print()
|
||||
|
||||
# Status report every 10 seconds
|
||||
rpi.io.dummy.reg_timerevent(status_report, 10000, prefire=True)
|
||||
|
||||
rpi.handlesignalend()
|
||||
rpi.mainloop()
|
||||
|
||||
Threaded Data Processing
|
||||
-------------------------
|
||||
|
||||
@@ -515,19 +472,6 @@ For slow operations, use threaded events:
|
||||
|
||||
rpi.io.trigger.reg_event(slow_task, as_thread=True)
|
||||
|
||||
Use Debouncing
|
||||
--------------
|
||||
|
||||
Always debounce mechanical inputs:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Good - Debounced button
|
||||
rpi.io.button.reg_event(callback, delay=30)
|
||||
|
||||
# Poor - No debounce (may trigger multiple times)
|
||||
rpi.io.button.reg_event(callback)
|
||||
|
||||
Handle Errors Gracefully
|
||||
-------------------------
|
||||
|
||||
@@ -543,18 +487,6 @@ Protect callbacks from exceptions:
|
||||
print(f"Error in callback: {e}")
|
||||
rpi.io.output.value = False # Safe state
|
||||
|
||||
Check IO Existence
|
||||
------------------
|
||||
|
||||
Verify IOs exist before registering events:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
if "optional_button" in rpi.io:
|
||||
rpi.io.optional_button.reg_event(callback)
|
||||
else:
|
||||
print("Optional button not configured")
|
||||
|
||||
Clean Up Threads
|
||||
----------------
|
||||
|
||||
|
||||
@@ -24,13 +24,12 @@ Quick Example
|
||||
**Cyclic Programming**::
|
||||
|
||||
import revpimodio2
|
||||
rpi = revpimodio2.RevPiModIO(autorefresh=True)
|
||||
|
||||
def main(ct):
|
||||
if ct.io.button.value:
|
||||
ct.io.led.value = True
|
||||
|
||||
rpi.cycleloop(main)
|
||||
revpimodio2.run_plc(main)
|
||||
|
||||
**Event-Driven Programming**::
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ Installation
|
||||
System Requirements
|
||||
===================
|
||||
|
||||
* Python 3.7 or higher
|
||||
* Python 3.2 or higher
|
||||
* Revolution Pi hardware (Core, Core3, Connect, Compact, Flat)
|
||||
* piCtory configuration tool
|
||||
|
||||
@@ -24,6 +24,9 @@ Log out and log back in for the group change to take effect.
|
||||
Installing RevPiModIO
|
||||
=====================
|
||||
|
||||
RevPiModIO is preinstalled on your Revolution Pi. It is distributed as debian package and will be
|
||||
updated by `apt`.
|
||||
|
||||
Using pip
|
||||
---------
|
||||
|
||||
|
||||
@@ -65,8 +65,6 @@ For continuous operation, use a cyclic loop:
|
||||
|
||||
import revpimodio2
|
||||
|
||||
rpi = revpimodio2.RevPiModIO(autorefresh=True)
|
||||
|
||||
def main_cycle(ct: revpimodio2.Cycletools):
|
||||
"""Called every cycle (default: 20-50ms)."""
|
||||
|
||||
@@ -91,7 +89,7 @@ For continuous operation, use a cyclic loop:
|
||||
print("Program stopped")
|
||||
|
||||
# Run cyclic loop
|
||||
rpi.cycleloop(main_cycle)
|
||||
revpimodio2.run_plc(main_cycle)
|
||||
|
||||
Event-Driven Program
|
||||
--------------------
|
||||
|
||||
Reference in New Issue
Block a user