Search code examples
androidmultithreadingbluetoothinputstream

Counter running in thread, driven by Arduino signals, skips the first several numbers


I have established a Bluetooth connection between Arduino (HC-05 Bluetooth module) and my Android application.

Every time Arduino sends a signal (the signal is just the number 72) then my Android app reads this signal (as bytes in an InputStream) and sets a "counter" variable to counter = counter - 1.

I created a thread that does this.

The problem is:

If for example I set the counter to 30 and start the Thread, the first 3-4 subtractions from 30 happen in milliseconds (they are not synced with the Arduino signals). But from 26 and on everything is perfectly synced and works as expected.

I tried a different Thread.sleep() times. Bigger sleep times make the problem worse (more subtractions happen in milliseconds). Lower sleep times are better, but still, don't solve my problem.

Why thread is out of sync for the first 3-6 subtractions and synced for all the others?

Some (maybe) useful infos:

There are 4 buttons. "Connect", "Disconnect", "Start" and "Stop".

  1. "Connect": Establish a connection through a BluetoothSocket with the HC-05.
  2. "Disconnect": Closes this connection.
  3. "Start": Starts the thread that listens to InputStream data from HC-05.
  4. "Stop": Stops this thread.

My code (the Thread code). If someone needs any other part of code please ask for it:

//CONNECT
arduinoSocket?.connect()
Toast.makeText(this, "Επιχειρείται σύνδεση με τον Mετρητή...", Toast.LENGTH_LONG).show()
if (!arduinoSocket!!.isConnected) {
    startbutton.isEnabled = false
    stopbutton.isEnabled = false
        Toast.makeText(this, "Σύνδεση απέτυχε.", Toast.LENGTH_SHORT).show()

    }
else {
    val t = Thread(Runnable {
        while(t_control == 1) {
            if (arduinoSocket.inputStream.read() == 72) {
                counter -= 1
                runOnUiThread {
                    ant_met.text = counter.toString()

                }
            }
        }
        Thread.sleep(50)
    })

Solution

  • I think the problem is on the Arduino side. There is an OutputStream type setup in the Arduino side as well I believe. From my experience, while coding in Arduino, I had to keep a buffer which works as an OutputStream. When the connection is being established, the buffer in the Arduino side is filling up with some pulses which are being stored in the buffer. Once the connection is getting established, the Arduino side buffer is sending out all the elements stored in the buffer at once and hence you are getting the first 3-6 signals in milliseconds.

    This can be easily avoided using some workaround on either side. The Arduino may clear the data stored in the buffer already after a connection has been established.

    If you do not want to change the Arduino side code, then do a similar thing in your Android side. Just read all the elements from the initial InputStream and after some time start your original Thread when the initial buffer in the Arduino is cleared.

    // Clear the initial buffer
    val t_init_control = 1
    val t = Thread(Runnable {
        while(t_init_control == 1) {
            arduinoSocket.inputStream.read()
        }
    })
    
    Timer().schedule(object : TimerTask() {
        override fun run() {
            // Stop the init thread
            t_init_control = 0 
            startNewThreadHere()
        }
    }, 2000)
    
    // This is the original thread where you want to keep the track of the pulse from Arduino
    fun startNewThreadHere() {
        val t = Thread(Runnable {
            while(t_control == 1) {
                if (arduinoSocket.inputStream.read() == 72) {
                    counter -= 1
                    runOnUiThread {
                        ant_met.text = counter.toString()
    
                    }
                }
            }
        })
    }
    

    This is just a pseudo code to explain the idea. Hope that helps!

    Update

    Here's how the problem was solved later. I am quoting from the comment section of this answer.

    I sent a Boolean to Arduino in order to determine when to start sending packets of data. In that way, Arduino starts sending data right after opening the InputStream in Android. Hence, there is no flood of "non-transmitted" bytes.