1

Currently I'm working on a application for my RPi which will be monitoring a set of GPIOs in real-time where the exact time when the GPIO turns HIGH is crucial for my application.

The actual date is not important when the specific event happen, instead the exact time relative to the other events is. (i.e the data recorded will be shown in a graph where the spacing between the events should be as exact as possible.)

I believe it will help if I create a separate listener thread for each GPIO I want to monitor. What can be a bit tricky is that two events might occur on two (or more) different GPIOs simultaneously, which my belief is that it can be solved somewhat by using different threads.

Another piece of information worth sharing is that I'm using Java with the PI4J library. Is there a better way to implement this specifically or is this way fine for my particular application? I don't know very much about the RPi hardware and what it really is capable of, so my ultimate goal is to find the fastest and the least CPU demanding solution as possible. And where the most important thing is time, my tolerance of accuracy is about 5-10 ms AT MOST.

Because of the fact my application is multi-threaded if this is the way to go I believe the accuracy might drop the more threads I have, because it will put more stress on the poor little RPi. Is this significant for this kind of application?

To break this down, my question is if a multi-threading environment is a ideal/decent solution when listening separately to multiple GPIOs in real-time?

I'd like your input on this because performance in this application is very significant to keep the real-time functionallity.

3 Answers 3

0

Java seems to have problems with garbage collection which perturbs any attempt at real-time data capture.

You don't say much about the number of gpios and the relative frequency of events. If you don't have a series of events triggering within a few microseconds of each other you may get C and interrupts to work.

The most robust solution I'm aware of at the moment to monitor the Pi's user gpios (gpios 0-31) is my pigpio library. It should capture the data. I'm assuming the additional processing required is within the Pi's capabilities.

Video of pigpio captured data being displayed in "real-time".

See http://www.raspberrypi.org/forums/viewtopic.php?f=81&t=63203 for a relevant post from someone also trying to capture data with PI4J.

An added note.

There is no reason to write any C at all. If you use the pigpio daemon all control and data can be routed through pipes or sockets.

For instance a pipe is just a file. Issue commands by writing to /dev/pigpio, read the command result from /dev/pigout and notifications from /dev/pigpioX.

The following (non-error checking) Python shows one way of using the pipe interface.

Note, the pigpio daemon must be running (sudo pigpiod) and if there is nothing happening on your gpios you won't get any output.

#!/usr/bin/env python

import struct
import time

control = open("/dev/pigpio", "w")
result  = open("/dev/pigout", "r")

control.write("no\n")      # All pipe commands must be ended with a line feed.
control.flush()            # Force message through the pipe.
h = int(result.readline()) # Read result (handle).

if h >= 0: # Valid notification handle received.

   notify = open("/dev/pigpio{}".format(h)) # Read notifications from here.

   # Specify gpios for which notifications are required.
   control.write("nb {} {}\n".format(h, -1)) # -1 is all gpios.
   control.flush()                           # Force message through the pipe.
   result.readline()                         # Discard result.

   start = time.time()

   while (time.time() - start) < 30: # Run for a few seconds.

      msg = notify.read(12) # Read next notification.

      if len(msg) == 12:

         S, fl, t, v = struct.unpack("HHII", msg)

         # Ignore sequence number and flags for quick test.

         print("Tick={:010d} gpios={:032b}".format(t, v))

   control.write("nc {}\n".format(h)) # Close notification.
   control.flush()                    # Force message through the pipe.
   result.readline()                  # Discard result.

   notify.close()

result.close()
control.close()
6
  • Thank you, I'm using Arch Linux OS and I've also asked this question to get more knowledge about how Linux handles time and how it can be synchronized via a UDP NTP Time Server etc. The number of GPIOs is around 4-6 but CAN be more, and the frequency is really hard to tell, since it can differ from very low and very high and sometimes zero.
    – Linus
    Jul 25, 2014 at 10:24
  • And if I choose to handle the monitoring in C with your library, would JNI be a good way to call the functions? Because I have alot of other stuff going on to process the data and upload it to a database etc.
    – Linus
    Jul 25, 2014 at 10:25
  • I'm afraid I don't even know what JNI stands for so I'm obviously not the person to offer advice on that. In your situation I'd probably start pigpio as a daemon then use the pipe or socket interface to collect the data. Pipe if running on the local machine, socket if running over the network.
    – joan
    Jul 25, 2014 at 14:57
  • Okay, thanks for your suggestion. Basically Java Native Interface (JNI) enables one to call C/C++ code from Java, in that case I could write a function in C to get some samples via pigpio, it also enables me to handle the low-level stuff in C and the network stuff in Java.
    – Linus
    Jul 25, 2014 at 18:08
  • I have added an example of using pipes showing that you don't need C at all. You could do the same as the Python within Java.
    – joan
    Jul 26, 2014 at 8:08
0

Your application of the real-time term seems to be correct to the sense that real-time is not necessarily very fast as many believe, but it is something that has to be done in a specific time-frame, be it microsseconds, be it seconds, be it hours.

Your 5-10ms time requirements is not really fast, but your real-time constraint have to be taken in account.

Java is not really the nicest play for the RPi, being very heavy on the processing and memory sides of it.

If, as you say, you need to be sure that your signals are processed in the specified time frame, you should take a look at real-time solutions, which neither the stock Linux kernel, nor the Java Virtual Machine are of any use for.

It is true that 5-10ms are big for the usual application, but you should consider that in a non real-time system, some runaway process, some crashing VM or blocked I/O call can take much longer than that time frame to solve and, even if your average tested response time is within that requirements, you may from time to time, face an exceeded response time situation for your cyber-physical interaction.

If it is crucial for your application to stay in that RT constraints, neither the stock Linux kernel, nor Java will be a good fit for a development solution.

Being that the case, you should think of real-time solutions. I have been in that position before and what I chose to use is a lower level RT data acquisition and actuation sub-system and a higher level supervisor that received information from this lower level out of a real-time context.

I use Xenomai as real-time supervisor, you can download a SD-ready image from this link and test it on your RPi. I then developed the acquisition and actuation sub-systems under RT Xenomai and the higher level supervisory/communication in Erlang, which is itself a soft-real-time virtual machine.

In a less constrained real-time application I used Erlang top to bottom. The Erlang virtual machine is a soft real-time interpreter, and has given very good and steady results on my tests, when it is not crucial to be in the time frame. It has very good support on Raspbian.

6
  • Thank you, this seems like a very ambitious solution for me, since I can't physically reach my RPi easy, I use SSH to communicate, it would solve my problem though, I would need to redo quiet a lot of work, which may be fine if it was absolutely inconceivable for me to accept anything else. But I believe, since my application will log many thousand entries every day, one mistake in say 5000-7000 thousand, wouldn't affect the statistics at all. For this particular application, using a low-level programming language like C and a "real-time" library is good enough for me.
    – Linus
    Jul 26, 2014 at 17:03
  • Just to clarify: with Xenomai you still have everything a full Linux offers (SSH, X, whatever!), you just have the additional real-time capability. And you can use C for the RT programming under Xenomai, that's actually pretty well supported and documented.
    – Marco Poli
    Jul 27, 2014 at 7:35
  • @Marco Poli. I haven't heard of anyone using Xenomai on the Pi to do data sampling. Could you point to any experiments which show the accuracy of the time-stamped data?
    – joan
    Jul 27, 2014 at 8:53
  • This paper is the best reference I found on comparing different RT strategies and solutions. It does not use the Pi, but I couldn't find a significant reason why results wouldn't apply.
    – Marco Poli
    Jul 27, 2014 at 13:00
  • Interesting. Yes, I can't see why the relative benchmarks wouldn't be similar on the Pi. However I feel that neither of the tests (pulse generation and timing events boundary to boundary) are directly relevant to the OP's data sampling needs.
    – joan
    Jul 27, 2014 at 21:49
0

Pi4J supports Listeners for GPIO events implemented by interrupts in the library. Check this example. So you don't need to create multiple threads to bussy check for GPIO events. Also as the CPU only has one core your threads could not even be executed in real parallel.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.