Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inaccurate interrupt detection after sometime of being idle #26

Open
adonespitogo opened this issue Apr 14, 2018 · 12 comments
Open

Inaccurate interrupt detection after sometime of being idle #26

adonespitogo opened this issue Apr 14, 2018 · 12 comments

Comments

@adonespitogo
Copy link

Hi, I'm trying to interface a multi coin acceptor with Espressobin. This coin acceptor emits pulses for every coin inserted. For example 1 peso coin (I'm in philippines) pulses 0 for 20ms and then pulses 1 for 100ms (using 'both' edge). It turns the GPIO input to 0 for 20ms and turns to 1 for 100ms. It does this one time for 1 peso coin and 5 times for 5 peso coin.

So if you print the value of 'both' edge every time an interrupt occurs, this is the output:

1 peso coin:

0
1 (after 20ms)

5 peso coin:

0
1 (after 20ms)
0 (after 100ms)
1 (after 20ms)
0 (after 100ms)
1 (after 20ms)
0 (after 100ms)
1 (after 20ms)

The problem is that sometimes, some of the interrupts are not detected by the epoll library when I'm no longer interacting with the coin acceptor after sometime. What happens is, for example inserting a 5 peso coin to the multi coin acceptor results to:

1 (after 20ms) - it skipped the first `falling edge` and/or
1 or 0 (after 120ms) - it skipped the falling/rising edge detection
0 (after 100ms)
1 (aftter 20ms)
0 (after 100ms)
1 (after 20ms)
0 (after 100ms)
1 (after 20ms)

I think the interrupt detection job is somewhat put to background or something that's why it can't properly detect the pulses when there is no activity for some time. In the next consecutive insertion of coins, it properly detects the coins again.

I can confirm that the problem is not the circuit or the coin acceptor because this doesn't happen when I use the same schematics on raspberry pi's GPIO and a python script.

I'd just like to know if you have any idea on top of your head what might be the cause of this issue.

@fivdi
Copy link
Owner

fivdi commented Apr 14, 2018

I think the interrupt detection job is somewhat put to background or something that's why it can't properly detect the pulses when there is no activity for some time.

I haven't seen something like this in the past. This doesn't however mean that it's not happening.

I'd just like to know if you have any idea on top of your head what might be the cause of this issue.

Do the pulses from the coin acceptor bounce? If so, this may explain what's happening.

There is a delay between point in time when an interrupt occurs and point in time when the callback passed to the Epoll constructor is called. Between those two points in time the pin state may change. If the pin state changes between these points in time then the value read from the GPIO will not be the expected value. This can happen with momentary push buttons that bounce. Perhaps there is a similar effect with the coin acceptor.

@adonespitogo
Copy link
Author

adonespitogo commented Apr 14, 2018 via email

@fivdi
Copy link
Owner

fivdi commented Apr 14, 2018

Let's leave the issue open. I'll take a closer look at some point to see if something goes wrong when the process is inactive for a long period of time.

Thank you for reporting this issue.

@adonespitogo
Copy link
Author

adonespitogo commented Apr 14, 2018 via email

@fivdi
Copy link
Owner

fivdi commented Apr 14, 2018

@adonespitogo above you mention the following:

I think the interrupt detection job is somewhat put to background or something that's why it can't properly detect the pulses when there is no activity for some time

Approximately how long is it necessary to wait before the issue can be seen?

@adonespitogo
Copy link
Author

adonespitogo commented Apr 14, 2018 via email

@adonespitogo
Copy link
Author

adonespitogo commented Apr 14, 2018 via email

@fivdi
Copy link
Owner

fivdi commented Apr 14, 2018

Thanks for the information.

I'll implement a stress test and run it for a several hours to see what happens. The pulses from the coin acceptor could be generated by a second Raspberry Pi or an AVR microcontroller.

@adonespitogo
Copy link
Author

This is my code by the way, I believe this might be of use as reference for your stress test:

'use strict'

const Q = require('q')
const payment = require('./payment.js');
const config = require('./config/config.json')
const Gpio = require('onoff').Gpio

module.exports.init = function () {

  let coinslot = new Gpio(451, 'in', 'both')

  let time_now = 0
  let last_detect_time = 0
  let has_detected = false
  let diff = 0
  let current_total = 0
  let interval = 100
  let prev_val = 1

  function checkDoneInsert() {
    if (has_detected) {
      time_now += interval
      diff = time_now - last_detect_time

      if (diff > 1000) {

        console.log('payment: ', current_total)
        payment.received(current_total);

        current_total = 0
        diff = 0
        time_now = 0
        last_detect_time = 0
        has_detected = false
      }
    }
  }

  function onChange(val) {
    if (val === 1 && prev_val === 0) {
      has_detected = true
      last_detect_time = time_now
      current_total += 1
    }

    prev_val = val

  }

  coinslot.watch(function (err, val) {
    if (err)
      console.log(err)
    else
      onChange(val)
  })

  setInterval(function () {
    checkDoneInsert()
  }, interval)

  return Q()

}

@fivdi
Copy link
Owner

fivdi commented Apr 28, 2018

After some experimentation I think the most likely cause for failing to detect some of the pulses from the coin acceptor is blocking synchronous code.

coin-acceptor.c is a program that can be used to simulate the coin acceptor on an atmega328p. Every two seconds the program will generate five pulses to simulate a five peso coin. The program stops after simulating 10.000 coins.

coin-counter-success.js successfully detects the pulses for 10.000 five peso coins.

coin-counter-fail.js fails to detect all the pulses for 10.000 five peso coins. Each pulse is low for 20 milliseconds and high for 100 milliseconds. The program fails to detect approximately 7% of the pulses. The failures occur because the program blocks the main JavaScript thread by executing synchronous code for 30 milliseconds once per second. The 30 milliseconds of blocking is longer that 20 milliseconds for which the pulse is low and the JavaScript code doesn't get around to processing some of the falling edges before the rising edges occur.

The last 16 lines of output for one run of coin-counter-success.js:

fallingPulses: 49975, risingPulses: 49975, errors: 0
fallingPulses: 49975, risingPulses: 49975, errors: 0
fallingPulses: 49980, risingPulses: 49980, errors: 0
fallingPulses: 49980, risingPulses: 49980, errors: 0
fallingPulses: 49981, risingPulses: 49981, errors: 0
fallingPulses: 49985, risingPulses: 49985, errors: 0
fallingPulses: 49985, risingPulses: 49985, errors: 0
fallingPulses: 49990, risingPulses: 49990, errors: 0
fallingPulses: 49990, risingPulses: 49990, errors: 0
fallingPulses: 49992, risingPulses: 49991, errors: 0
fallingPulses: 49995, risingPulses: 49995, errors: 0
fallingPulses: 49995, risingPulses: 49995, errors: 0
fallingPulses: 50000, risingPulses: 50000, errors: 0
fallingPulses: 50000, risingPulses: 50000, errors: 0
fallingPulses: 50000, risingPulses: 50000, errors: 0
fallingPulses: 50000, risingPulses: 50000, errors: 0

The last 16 lines of output for one run of coin-counter-fail.js:

fallingPulses: 46503, risingPulses: 49985, errors: 0
fallingPulses: 46505, risingPulses: 49987, errors: 0
fallingPulses: 46505, risingPulses: 49987, errors: 0
fallingPulses: 46509, risingPulses: 49992, errors: 0
fallingPulses: 46509, risingPulses: 49992, errors: 0
fallingPulses: 46511, risingPulses: 49995, errors: 0
fallingPulses: 46513, risingPulses: 49997, errors: 0
fallingPulses: 46513, risingPulses: 49997, errors: 0
fallingPulses: 46518, risingPulses: 50002, errors: 0
fallingPulses: 46518, risingPulses: 50002, errors: 0
fallingPulses: 46518, risingPulses: 50002, errors: 0
fallingPulses: 46518, risingPulses: 50002, errors: 0
fallingPulses: 46518, risingPulses: 50002, errors: 0
fallingPulses: 46518, risingPulses: 50002, errors: 0
fallingPulses: 46518, risingPulses: 50002, errors: 0
fallingPulses: 46518, risingPulses: 50002, errors: 0

@fivdi
Copy link
Owner

fivdi commented Apr 28, 2018

epoll has its own thread for detecting events. The code in this thread could be modified to queue events for later processing. Events that occur when blocking JavaScript synchronous code is executing for prolonged periods of time would then be queued and could be processed later without getting 'lost'.

@adonespitogo
Copy link
Author

Wow thanks for taking the time to test this. I'm really looking forward for the fix for this. Right now I'm using polling to detect the coins and it's taking a bit of processing resources by constantly reading the gpio value every 10ms.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants