New: the AI firewall watches the whole platform and explains each incident in plain words. See how it works

Ciarán Walsh

ciaran55

@ciaranwalsh55 · Joined June 2025

Newcomer

Smart-city engineer · energy

Topics
9
Replies
68
Points
0
Newcomer10 points to Member

Forum Replies Created

Viewing 8 posts – 61 through 68 (of 68 total)

Screen blanking won’t do it. Classic Wi-Fi power saving on the Pi’s Broadcom chip, I had the same with a Pi 3B+ in a pump house. The Pi doesn’t sleep, the Wi-Fi does, and incoming packets get delayed or lost. Your paho client sends a ping every 60 s, the answer doesn’t come back in time, Hermetry sees nothing within the keepalive and closes the session, hence keepalive_timeout. Your SSH wakes the radio up, which is why everything comes back then.

Check it:

iw wlan0 get power_save
Power save: on

Turn it off for good on Bookworm with NetworkManager:

sudo tee /etc/NetworkManager/conf.d/wifi-powersave.conf <<EOF
[connection]
wifi.powersave = 2
EOF
sudo systemctl restart NetworkManager

(2 means disabled.) If you’re on an older image with dhcpcd, put iw wlan0 set power_save off in a script that runs after the network is up.

Also make your client reconnect on its own: client.reconnect_delay_set(1, 120) and loop_forever or loop_start, so a short drop fixes itself.

Accepted solution♥ 9

That’s typical with those TT motors. No two run at the same speed for the same PWM, the L298N drops a couple of volts differently per channel, the floor and the wheel diameters differ, and all of it changes with battery voltage. A fixed trim only fits one battery level, as you saw. Swapping the motors and still drifting right points at something besides the motors too (wheel diameter, a caster, the floor).

Better motors won’t fix open loop. What fixes it is measuring the wheels: TT motors with encoder discs and slotted optical sensors cost a few pounds. Count ticks on both wheels and correct the PWM so the counts stay equal. A simple proportional correction is enough for a corridor:

from gpiozero import Motor, RotaryEncoder   # or DigitalInputDevice per sensor
import time
left, right = Motor(17, 18), Motor(22, 23)
enc_l, enc_r = RotaryEncoder(5, 6), RotaryEncoder(13, 19)
base, kp = 0.7, 0.002
while not arrived():
    err = enc_l.steps - enc_r.steps        # +: left ahead
    left.forward(max(0, min(1, base - kp * err)))
    right.forward(max(0, min(1, base + kp * err)))
    time.sleep(0.02)

If one cheap optical sensor per wheel (no direction) is all you have, count pulses with a DigitalInputDevice callback instead, direction is known anyway. For really straight runs, add an MPU6050 gyro and hold the heading. And if they’re rebuilding, swap the L298N for a TB6612FNG: much smaller voltage drop, so the battery lasts longer too.

While they’re at it, send the encoder counts per trip to Hermetry. A rising left/right difference on the same route is an early sign of a wheel or gearbox going.

Accepted solution♥ 7

David’s current sensor is a valid feedback source, but most contactors already have an auxiliary contact block, which is cheaper.

Wire an NO auxiliary contact to a PLC input (or use the current relay if the contactor can’t take an aux block). Then publish both values in the same message, every few seconds, not only on change:

{"sf1.cmd": 0, "sf1.fb": 1}

Alarm rule on the profile, in JSON mode since the form only does one comparison per severity:

"severities": [
{ "severity": "MAJOR",
"condition": { "any": [
{ "all": [ { "key": "sf1.cmd", "op": "==", "value": 0 }, { "key": "sf1.fb", "op": "==", "value": 1 } ] },
{ "all": [ { "key": "sf1.cmd", "op": "==", "value": 1 }, { "key": "sf1.fb", "op": "==", "value": 0 } ] } ] } }
],
"debounce": { "mode": "duration", "raise": 5, "clear": 5 }

That covers welded (off but running) and failed to pull in (on but stopped). The 5 s duration debounce covers the contactor’s pick-up and drop-out time. Duration debounce only moves forward when readings arrive, so the PLC has to keep reporting; with change-only reporting the alarm would wait for the next change.

Simpler alternative: let the PLC compute a discrepancy bit with its own timer (it needs it for the local interlock anyway) and alarm on sf1.discrepancy == true. Less JSON, one source of truth. Conditions are explained on Alarm conditions reference.

Accepted solution♥ 1
Viewing 8 posts – 61 through 68 (of 68 total)