Two way Bluetooth/Arduino communication

Hi all!

I have an arduino Zero with a touchscreen display and a HC-05 bluetooth module. The touchscreen displays a slider and accepts user input, no problem with that.

I created an app in App Inventor that has the same display as the arduino, a slider for user input. Adjust the slider in the app and via BlueTooth, the arduino receives the data, and changes the displayed slider to match the new input. That part is working.

I am now trying to get touchscreen data from the arduino into the app, and failing at this a bit.

When the touchscreen slider is moved, the arduino prints the data to the HC-05, and my app recieves the data and displays it. This is where my problem is, if there is no data from the HC-05, the display is blank in the app.

Here are my blocks for that part of the app:

The arduino side of things is kind of like this: (pseudo code)

if (touchscreen changed)
{
  update display
  print data to HC-05
}

The data is being sent to the app, in that as long as the slider is moved, the app is updated. But when the arduino sends no data, the fields in the app are blank, not displaying their last set values. This is where my problem is.

When no data is sent from the arduino, the fields in the app that should display the last data sent from the HC-05 are blank.

Not sure what I am missing here....
Thanks for any help,
Randy

Hi

Something strange there - your code currently will do nothing unless data is received, so your screen should then just stay as-is. It maybe that the number of bytes sent is not constant (not always 2) when the screen goes blank, i.e. the 2 byte value being meaningless.

So, what exactly is the App Receiving? Since you are setting two components Text, is it a single character? What is the format? UTF8?

What I suggest you do is end your data from Arduino with a blank end of line thus:

Serial.print("MyData");
Serial.println(); 

In App Inventor, on Screen initialisation:
LineEnd

In the Receive Text Block, set the value to -1 (instead of 2). This tells the App to read the data until it gets to the NewLine Flag we have ended the data with.

The data sent from arduino is a 2 digit integer that will always be between 50 and 99. Here is my ardunio code:

    sliderValue = map(p.x, 70, 250, 50, 99);    // map x touchscreen value

    // limits on slideValue
    if (sliderValue < 50)
    {
      sliderValue = 50;
    }
    else if (sliderValue > 99)
    {
      sliderValue = 99;
    }

    if (prevSliderValue != sliderValue)
    {
      moveSlider(map(sliderValue, 50, 99, 70,250));
      
      displaySliderValue(sliderValue); 

      prevSliderValue = sliderValue;

      Serial1.println(sliderValue);   // send to bluetooth
    }

Anyway, originally, I had things set up like you suggested:

Originally, that is how I had it set up, as I was following the example found here:
https://groups.google.com/forum/#!msg/mitappinventortest/lVaCyAeWm_4/ADjvy05wAwAJ

But I went back in designer and set the BluetoothClient1's DelimiterByte is set to 10. I also changed the blocks to what you suggested:

Which is how I tried the first time, and it didn't work. Now it does work. I'm not sure where I went wrong, but for now this part is working...

Is there any other ways to check for new Bluetooth data other than the timer method? In AI2 my Clock1 timer's interval is set to 100, (I assume that value is in milliseconds?), so it's checking for data 10 times a second. At this interval, the app can lag behind what is happening on the touchscreen. Clearly, I should shorten the interval to decrease the lag, but isn't that wasting resources? If I set the interval to be 10, isn't the app now checking 100 times per second for new data? Is there any sort of interrupt system in AI2?

Currently, my arduino is constantly monitoring for touchscreen input, but I plan to change that to being interrupt driven. When the touchscreen is touched, an Interrupt Service Routine (ISR) will execute, make the changes as per touchscreen data, then return to normal processing tasks.

AppInventor appears to lack something like this, am I correct?

Thanks for the help thus far!

Randy

Hello Randy

Well, @ 100 milliseconds, you are on the limit that App Inventor can process anyway.

You are using Classic Bluetooth and that's where the limitations are. If you upgrade to BLE, then the App can sit and wait for data without needing a timer.

What value does BTdata have when it is "blank"?

You try
if BTdata != 0
SliderValue = BTdata
Output = BTdata

As it says @ChrisWard , try BLE. example with HM-10

Look example Arrhythmia with BLE,

Here, example 19, interrupts with Arduino UNO and HC-06

Can you clarify this:

Does this mean my App Invertor app can't process any faster? If I set the timer to 10 milliseconds, can the app process at that speed?

But can the app process the data faster? I'm just trying to figure out where the lag is in data sent from arduino to the app.

@Juan_Antonio
Thank you for bringing that information to my attention. I will be looking into BLE. You have a lot of helpful examples posted in that thread.

Thanks,
Randy

... It means at that speed, your Android processor is going to struggle. You do not need to receive data every 100 milliseconds if your setup is an interrupt system as data will only be sent when it is available.

What does your App do with the data on receipt?

When my app receives the data, it updates the value displayed in the app and the app's slider input as well. Here are my blocks:


The blocks on the left are basic bluetooth connection stuff, copied from blocks I found here, on this forum. The blocks on the right is where the action is.

When the value of the app's slider is changed, those changes are sent to the arduino. The arduino updates the screen with the new values. That much is almost lag free. (first set of left side blocks)

When the slider on the ardunio's touchscreen is changed, those changes are sent to the app, which updates it screen with the values. (second set of left side blocks)

This is where I experience the noticeable lag at, updating the app with the data from the ardunio. Please note in that bit of blocks, I have some code I was messing with to overcome the lag.

My thinking on that code is something like this....
After the app updates itself, recieve all new data from the arduino and discard all data but the last 2 bytes, which would be my 2 byte number the arduino sends. (well, 2 digits, plus the eol character) which is the latest data from the arduino.

The code to remove the unneeded data doesn't work correctly, but I haven't analyzed the results yet to see why it's not working. I shall look into it the next time I work on the app.

Thanks for all your help!
Randy

How much time is actually lost? It is possible that there is lag at the Ardunio end too - for a start, everything will slow down as the processor gets hotter so if you haven't already done so, try a cooling fan (a desktop fan would do, just to see). Also, the main loop of the Sketch - how do you regulate the timing?

...and:

Even if it was possible to do that cleanly, the human eye would object to watching it! It's uncomfortable watching changes every second.

Chris, thanks for your help and advice!

I overcame the lag in the app, this was what part of my last post was about. I just had a problem with the logic in the blocks posted in my last post. I re-looked at it today and fixed it.

After the app updates itself and the timer goes off again, there can be several values waiting to be handled. I now use a while loop assigning the data to my variable, while data is available. When the last data that is available is read, the loop exits with the variable containing the latest data, then the update takes place. Before, it was updating for every data value sent.

blocks

Now I'll look closer at the arduino code and a similar approach there.

Thanks again,
Randy

1 Like

That's a well defined fix Randy :sunglasses:

In the Ardunio main loop, use elapsed milliseconds rather than delay().

Ok, I am back to working on this app. I stopped working on the app to focus on other stuff in the project, now I am turning my focus back to the app. When I stopped working on this app, I noticed I had one problem with it - the app was sending data via bluetooth when it shouldn't send any data.

To summarize my project: I have an arduino with a touchscreen display and a bluetooth module. On the touchscreen display there is a slider, when the slider is adjusted, the new values are sent to the app via bluetooth. The app has a slider, when it's slider is changed, the new values are sent to the arduino, via bluetooth, and the arduino touchscreen is changed.

Everything works fairly well. Adjust the arduino's touchscreen slider and the app's slider adjusts to match the arduino's slider. Adjust the app's slider, and the ardunio's touchscreen slider adjusts to match that of the app. But there is one small glitch to it....

When the arduino's slider is changed, that change is sent to the app. The app uses a timer to keep checking for data, once data is received, the app adjusts the slider. When the app's slider changes, that triggers the slider.PositionChanged event that then resends the data back to the arduino. I need to stop the data from being sent back to the arduino.

Here are my blocks:

The upper two left blocks of code is where the problem is. Like I said, when the data is recieved, the slider in the app is changed, which then triggers the slider.PositionChanged event. I need to stop that event from happening if the slider was changed via bluetooth, and not by the app's slider. I need a way to detect if the app's slider is changed in the app and not by the arduino.

Thanks for any help,
Randy

Your global slider_value could be used to communicate between the receiving and transmitting sides of your app, if you declare it as the intended target value for the slider.

When BT_data arrives,

  • set global slider_value to BT_data's new value first
  • then adjust the slider component thumb to match BT_data, etc.

When Slider1 Position changed

  • test if the new thumb position differs from global slider_value.
  • If different, this is initiated from the phone, so
    adjust the new slider_value
    send the new slider value
  • else if thumb equals slider value
    do nothing

Thanks @ABG for your help! It now works as desired!

Randy