SK
Signal K9mo ago
Ed

engine RPM with pigpio library (edit: forget about pigpio)

Need help with an idea. The idea is to get engine RPM data into SignalK via a python script and the pigpio library. https://abyz.me.uk/rpi/pigpio/index.html https://abyz.me.uk/rpi/pigpio/code/read_RPM_py.zip The raw signal comes from the alternator and the script already has functionality to multiply to get from pulses to RPM and also for averaging. A piece of hardware is needed to connect to a GPIO pin, preferably using an opto. I’ve got it working on my Pi which is also running SignalK-server, outputting a number. Where I’m stuck is with not knowing how to tie these two pieces together. Edit: the use of pigpiod made the Pi reboot within a minute. No error or logging at all. I continued with writing my own solution (read: copy/paste snippets from the internet)
25 Replies
Teppo Kurki
Teppo Kurki9mo ago
I think the easiest ways are - via UDP - wrap the python code as a plugin For UDP create a server data connection as Signal K, UDP. Then from python send sk delta messages For plugin use as base https://github.com/SignalK/sk-plugin-python-demo Output sk deltas to stdout You don’t need to publish the plugin, you can install from github or using npm pack
mats___a
mats___a9mo ago
Just a heads up that the pigpio library isn't working with RPi 5.
Jason_SV.Apres|Hunter336|WI
I believe the Openplotter team are looking at libgpiod - gpiomon instead of pigpio
Ed
EdOP9mo ago
I’ve looked at both options but sadly have no idea how to tackle this. I’m not a developer. Leaves me no other option than to use SensESP, which is overkill because the needed connection is very near the RPi. And an ESP32 with powersupply and sending over WiFi seems crazy. Oh well, it was just an idea.
Teppo Kurki
Teppo Kurki9mo ago
If you have working python example then it should be doable. Share your code?
Ed
EdOP8mo ago
Oh, it is not my code, I wish I could do that. It is what I linked in my original post: https://abyz.me.uk/rpi/pigpio/code/read_RPM_py.zip
sudo apt-get install pigpio python-pigpio python3-pigpio
sudo pigpiod <<- start daemon
sudo python read_RPM.py <<- outputs "RPM=..."
sudo apt-get install pigpio python-pigpio python3-pigpio
sudo pigpiod <<- start daemon
sudo python read_RPM.py <<- outputs "RPM=..."
So I do have above mentioned python script working with pigpio (outputs rpm on CLI) and also got your sk-plugin-python-demo working. But I have no idea how to combine those two.
Teppo Kurki
Teppo Kurki8mo ago
can you modify the script so that it outputs signalk delta format messages? they look like {"updates": [{"values": [{"path": "environment.airPressure","value": 1013}]}]}
Teppo Kurki
Teppo Kurki8mo ago
after that you configure manually (by editing settings.json) sk server to launch the script and use its output as a data connection per the example at https://github.com/SignalK/signalk-server/blob/master/settings/commandline-provider-settings.json
GitHub
signalk-server/settings/commandline-provider-settings.json at maste...
An implementation of a Signal K central server for boats. - SignalK/signalk-server
Ed
EdOP8mo ago
The script is now modified and outputs: {"updates": [{"values": [{"path": "propulsion.main.revolutions", "value": "0"}]}]} {"updates": [{"values": [{"path": "propulsion.main.revolutions", "value": "0"}]}]} {"updates": [{"values": [{"path": "propulsion.main.revolutions", "value": "0"}]}]} (on my desk so no input from tacho to GPIO) The editing of settings.json also succeeded and am now seeing:
No description
Ed
EdOP8mo ago
Cool! Should the python script output just a single result and exit? Atm it is looping and producing output constantly every 2 secs (definable). Looks like the script is constantly restarted every minute:
Apr 12 13:30:01 raspberrypi signalk-server[100930]: |/home/pi/read_RPM.py| exited with 0
Apr 12 13:31:01 raspberrypi signalk-server[100930]: |/home/pi/read_RPM.py| exited with 0
Apr 12 13:32:02 raspberrypi signalk-server[100930]: |/home/pi/read_RPM.py| exited with 0
Apr 12 13:33:02 raspberrypi signalk-server[100930]: |/home/pi/read_RPM.py| exited with 0
etc.
Apr 12 13:30:01 raspberrypi signalk-server[100930]: |/home/pi/read_RPM.py| exited with 0
Apr 12 13:31:01 raspberrypi signalk-server[100930]: |/home/pi/read_RPM.py| exited with 0
Apr 12 13:32:02 raspberrypi signalk-server[100930]: |/home/pi/read_RPM.py| exited with 0
Apr 12 13:33:02 raspberrypi signalk-server[100930]: |/home/pi/read_RPM.py| exited with 0
etc.
And in the Web-UI 'Server Logs' it shows as an error:
Ed
EdOP8mo ago
No description
Teppo Kurki
Teppo Kurki8mo ago
it should run forver and output data, one message per line
Ed
EdOP8mo ago
Ok, so that part is fine. Leaves the (error?) messages in the log. Any idea why it writes to the log like that? Almost there!
Teppo Kurki
Teppo Kurki8mo ago
Your script is exiting instead of running continuously
Ed
EdOP8mo ago
Yes, you were right. The script I adopted had a nifty while loop. Beyond me why anybody would have a RPM counter running for a minute and stop, but now it runs infinite. Thanks @Teppo Kurki for the help 👍 I've amended server.json with mentioned example. This works as expected. But because I want to do more than just write a static number I've amended the line for command into "command": "/home/pi/read_RPM.py". This also works, but not immediately. I first have to kill -9 the started process /usr/bin/python3 /home/pi/read_RPM.py From that point SignalK-server starts producing the path and value. So question is: Why does it not work from the (re)start of SignalK? It does get started right away, but doesn't do anything. No errors either. I've tried postponing the start of the script like this: "command": "sleep 10; /home/pi/read_RPM.py" but that didn't help. Oh, and when left alone, so no killing of the process, it does kinda start after two minutes or so but produces sporadic output.
Ed
EdOP8mo ago
No description
Teppo Kurki
Teppo Kurki8mo ago
i've never used pigpio myself, but afai understand it has a background daemon process and the code that uses it. my guess is that when sk server is stopped it and stops your script also that leaves something lingering you can try adding sudo killall pigpiod && sudo pigpiod && before your command to restart the daemon ( from https://abyz.me.uk/rpi/pigpio/download.html)
Ed
EdOP8mo ago
My script is now completely without pigpio; it made the Pi very unstable. So pure your example for settings.json where command is starting a very simple python script.
"pipedProviders": [
{
"id": "RPM-script",
"pipeElements": [
{
"type": "providers/execute",
"options": {
"command": "/home/pi/read_RPM.py"
}
},
{
"type": "providers/liner"
},
{
"type": "providers/from_json"
}
]
},
"pipedProviders": [
{
"id": "RPM-script",
"pipeElements": [
{
"type": "providers/execute",
"options": {
"command": "/home/pi/read_RPM.py"
}
},
{
"type": "providers/liner"
},
{
"type": "providers/from_json"
}
]
},
The script (don't laugh, I'm a beginner):
#!/usr/bin/python3

import time
import RPi.GPIO as GPIO
from datetime import datetime

GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.IN)

def count_frequency(channel):
global count
count += 1

count = 0
GPIO.add_event_detect(17, GPIO.RISING, callback=count_frequency)

while True:
tick = datetime.now().strftime('%Y-%m-%dT%H:%M:%S')
newcount = str(count)
data = '{"updates": [{"source": {"label": "dummy data","timestamp":"' + tick + '"},"values": [{"path": "propulsion.mainEngine.revolutions","value": ' + newcount + '}]}]}'
print(data)
count = 0
time.sleep(1)
#!/usr/bin/python3

import time
import RPi.GPIO as GPIO
from datetime import datetime

GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.IN)

def count_frequency(channel):
global count
count += 1

count = 0
GPIO.add_event_detect(17, GPIO.RISING, callback=count_frequency)

while True:
tick = datetime.now().strftime('%Y-%m-%dT%H:%M:%S')
newcount = str(count)
data = '{"updates": [{"source": {"label": "dummy data","timestamp":"' + tick + '"},"values": [{"path": "propulsion.mainEngine.revolutions","value": ' + newcount + '}]}]}'
print(data)
count = 0
time.sleep(1)
I have another python script that generates a frequency on a GPIO.output pin connected to GPIO17 for above script. For bench testing; works great. When signalk starts it starts the script but nothing happens until I kill the script.
Teppo Kurki
Teppo Kurki8mo ago
kill what script?
Ed
EdOP8mo ago
My python script named (see settings.json) /home/pi/read_RPM.py It looks like the script is started twice from settings.json:
No description
Ed
EdOP8mo ago
Seen with htop:
No description
Ed
EdOP8mo ago
When I completely stop signalk there is no such script left. Then I start signalk again and the scripts are back. One too many it seems. There really is only one such line in settings.json @Teppo Kurki Have you ever tried to use a python script by defining like: "command": "/home/pi/script.py" in settings.json? Even a minimalistic script with a conversion of the bash command: while true; do echo '{\"updates\": [{\"source\": {\"label\": \"dummy data\",\"timestamp\":\"'date +'%Y-%m-%dT%H:%M:%S''\"},\"values\": [{\"path\": \"environment.airPressure\",\"value\": 1013}]}]}'; sleep 1; done to python doesn't work. I've made sure the continues output is exactly the same when run from the command line.
Teppo Kurki
Teppo Kurki8mo ago
sorry about missing your comments above i just tried running
#!/usr/bin/python3

import json

import time
while 1:
print('{"updates":[{"values": [{"path": "foo.bar","value": 3.14}]}]}', flush=True)
time.sleep(1)
#!/usr/bin/python3

import json

import time
while 1:
print('{"updates":[{"values": [{"path": "foo.bar","value": 3.14}]}]}', flush=True)
time.sleep(1)
it is launched once on my Mac and works as expected you can try adding debug key signalk:streams:execute in Server Log, activate Persist debug settings and restart. you should be getting debug logging about launching the script then you can use ps or pstree to see the process hierarchy: is the sk node process really launching to instances of your script are you sure you are looking at the correct settings.json? break the json by removing for example a { and restart, does the server start?
Ed
EdOP8mo ago
Thank you Teppo. Still don't know what I did wrong but your example helped me out. Might anyone be following; with below code a rudimentary RMP counter reads pulses from GPIO without the need of any daemon running. Do take care of proper (voltage, spikes) protection of the port though!
#!/usr/bin/python3

import RPi.GPIO as GPIO
import json
import time

GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.IN)

def count_frequency(channel):
global count
count += 1

count = 0
GPIO.add_event_detect(17, GPIO.RISING, callback=count_frequency)

while 1:
print('{"updates":[{"values": [{"path": "propulsion.mainEngine.revolutions","value": ' + str(count) + '}]}]}', flush=True)
count = 0
time.sleep(1)
#!/usr/bin/python3

import RPi.GPIO as GPIO
import json
import time

GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.IN)

def count_frequency(channel):
global count
count += 1

count = 0
GPIO.add_event_detect(17, GPIO.RISING, callback=count_frequency)

while 1:
print('{"updates":[{"values": [{"path": "propulsion.mainEngine.revolutions","value": ' + str(count) + '}]}]}', flush=True)
count = 0
time.sleep(1)
Last time updating this topic: Although above does work, it is inaccurate. Usable but the RPM-gauge (KIP) will never be stable but constantly moving back- and forth a little. This is due to the RPi running a full OS which is not real time processing. So an ESP32 (SensESP) is probably best option for me (no room for HALMET)
Want results from more Discord servers?
Add your server