2017년 5월 16일 화요일

Problem with handy-Bluetooth-Arduino-communicatíon


I programmed an app with the MIT App Inventor 2 and a Arduino UNO sketch that communicate over the HC-06 bluetooth modul to control a led stripe WS2812B 5050 RGB stripe with WS2811 controller.

Like it is adviced in different internet forums I created a handshake and in the UNO sketch there is  either communication with the handy or control of the led stripe because of sharing the same interrupt in the functions.

It always starts good, but after a few minutes the app hangs.

I debuged it and it seems that the app/handy does not work quiete right.

As you can see in the screenshot "Debug_App" the app stucks in the step that the event "Slider1_Blau" was triggered ("Label1_Schritt.Text" is set to "Blau"), the flag "global Anfrage" to start the first step of the communication is true.
Now the event "Clock1_Bluetooth_Handshake.Timer" should execute "call(BluetoothClient_HC_06.SendText)" and send "text("<")" but as you can see the "Label1_Schritt.Text" isn't set to "<" but still is "Blau".
Why does that happens? The timer event is triggered every 150 ms and if the flag "global Anfrage" is true it should execute the Bluetooth call!

As you can see in the screenshot "UNO_Handshake_Protokoll" the last communication has ended corretly ("a" is always the last step in the handshake and tells the app that the data "global Wert" was recieved) and no new char was recieved.

In the screenshot "Debug_Sketch" you can see that the sketch still runs betweens "empfange" (recieve) and "zeige" (controll led).

To me it looks like the sketch has finished the communication and has not lost anything but the app does not execute the bluetooth call. :-(

Does anybody has an idea?

Shall I upload the sketch and/or the ais file?






--
Your problem is that you are sending and receiving data within the same timer event. You must have a protocol that makes sure that you have received all data from your Arduino before you are sending new data. Otherwise some buffers will overflow, or other errors will occupy r. If this is enough information to solve your problem, fine, else attach your .aia and sketch.

--
Thanks for your answer.

I understood the timer event in that way that every time it is called it would run through and execute the step that is actually true by the flags. For my understanding a handshake is a step sequence and I thought the timer event with the flags would do it that way.. 

Since I don't know how to change my app (I tried two timer but it didn't help either.) it might be the best if I upload my app and sketch.
There is much of debugging stuff in it (all the labels), three variables for the communication (Kommunikation, Anfrage, Werte) and one variable for the data (Wert).
For the Bluetooth communication man has to write his handy Bluetooth mac adress into the text string.

The sketch has the loop with both the main functions "Empfang" (recieve) and "Anzeige" (control led). The function "Emfang" calls the function "Empfangsverarbeitung" while Bluetooth is available.The function "Empfangsverarbeitung" manage the handshake and asignes the data to variables.
If Bluetooth doesn't recieve anymore data or a before called led program (for example "leddimmen") is running the function "Anzeige" is called and calles itself the subfunctions to control the led.

It took me a lot of time and struggle to come to these conclusions because I'm not a professional programmer. In the top of the sketch I'm mentioning the sources where I sampled all the information. So I'm sad that it doesn't work.

Thanks for any help. Please tell me if I shall give more comments to my app or sketch or whether I should translate it complete in English.



--
My German is OK enough, that cannot be said of my amount of time available, and of my broken laptop which I need for this. So, please some patience.

--
Some preliminary remarks:
Since your app is working at startup, the problem must be in the timing and the communication.

Why do you connect the Arduino at initialize? Personally, I think it would be better to have a button for it. I am also missing a button for disconnect.
After connecting, you must set a global indicating that you are connected. This allows you to check in the timer event whether the Arduino is indeed connected. You could loose connection by walking away with you phone, or initially it may be slow to respond.

Then, my problem with your protocol is that you are sending and receiving in the same Timer event. There could be a delay somehow which then causes out-of-sync problems. So, When you are sending, you should not receive anything, and when you are receiving, you should make sure that you received everything before you start sending again. 

Which brings me to your ReceiveText, which always only receives 1 byte. But, if you have debug on, the Arduino sends a println, which is at least 2 bytes.

Then, there is quite a bit of repeated code. Put it in a procedure! I will send an example later. To be continued.

--
I also write the application to control the LEDs WS2818, do not know much about programming, but something I have created.

The code for the Arduino and Android app is here:
https://github.com/romi06/WS2812-bluetooth
and the source code of the application is a few posts below "Button color" code itself is probably a lot of mistakes but on my Samsung S2 works ok.
Maybe something useful to you.
Google translator

--
I looked further at your app and I found a few things that you should improve.
Connection: most people have a listpicker to show the possible BT devices, and that is what my example here uses:

Then, instead of all the similar code for the buttons, when clicked, you could do something like this the blocks above. Similarly you could make a procedure that covers the three sliders.
Then, the sending of data is always triggered by pressing a button or moving the slider. Therefore there is no need to do this in the clock.Timer event. That only makes things difficult.
What you should do, is check whether the Arduino is properly connected, send the stuff and then wait for a reply.

In the clock.Timer block you should always check whether the number of available bytes to retrieve is > 0 and if so, recieve all bytes that are available, like this:
I cannot check whether your sketch is alright, but if you have debug on, you should see what is going on in your Arduino and you could display that in a label for example (in the dosomethingwithtereceivedtext procedure).
Let us know whether you are making progress.

--
thanks for your effort. The sketch and the app look really interesting. Unfortunately the app is just a *.apk file so I can't see how the communication works. Second the app isn't either in English nor in German so I can't understand and handle it. 

--
This is what I made of your app, to make more clear what should be happening (see attached .aia).
But it could be very wrong, because I do not understand what the protocol with your Arduino is.
Could you describe it in simple terms?

Like: if App sends < then Bt responds s
Wait for response
Send values, etc.

Right now it seems that you could send a full command and what you receive back is just for debugging purposes, but I am not sure.

--
Thank you very much for your big effort.

Please let me first answer to your hints and in that way explain a little bit more of what I thought my app and sketch are supposed to do (but what they obviously not do). 
Maybe that way we find the error in my thoughts and can correct my app and sketch before we try to get your app running (It did run one cycle and then did nothing more.).

You wrote that I “send and receive data within the same timer event”.
My intention was to manage the circumstances that neither the app nor the sketch are all time ready to receive data.
In the timer event I have the handshake that is a step sequence. 
If a button or a slider is moved and no communication already happens (“Kommunikation” is false) the data are written to the variable “Wert” and the flag “Anfrage” and “Kommunikation” are set.
So now every time the timer event is running through the handshake is executed. The first time because the flag “Anfrage” is true now (and “Werte” not) the bluetooth function sends the start marker “<” to the sketch. It doesn't matter whether the sketch answers immediately.
Because the next time the timer event is triggered it is still in the step “Anfrage” (“<”). And if then the “s” from the sketch is received the flag “Anfrage” becomes false and “Werte” true. So the handshake sequence is in the next step.
So my intention was that at least after some time events the data should be exchanged between the app and the sketch. 

The sketch itself is primary in the “empfange” case to handle right away incoming data. 
It only jumps into the case “zeige” if new data has arrived (in function “Empfangsverarbeitung” in case “>” of the end marker) or a led control program like “leddimmen”  needs to be run. But the control comes back to “empfange” after each run through “zeige”.
And the led control programs are non blocking because of using a timer interrupt.
For the first few times all this seems to work like my debugging shows.

I did another debug to see whether the timer event still works even though the bluetooth call isn't made and now I can see that even the timer event stuck.
This is strange. Maybe the timer event and the bluetooth call hang each other up like the Serial or SoftwareSerial function and the led control function (FastLed and Adafruit_NeoPixel. I use NeoPixel_SPI from Nick Gammon) would hang each other up if used together because both need the same interrupt (like I learned in the internet forums).
But this question can probably only be answered by the MIT Inventor team.

The numberOfBytes is set to 1 because my handshake character are only 1 byte.
If I change it to 2 it doesn't work, it stuck.

The way I establish the bluetooth connection does work if both devices are already paired. I get a message from the notifier when the connection is done. And I don't think I lose it because I'm sitting right in front of PC, handy and Arduino.
For later on when I could use my app I would make the connection as you advised it so other family members could use the app on their phones. I do know the ListPicker method but be to lazy doing it every time. But thanks for your hint.

The way you use the button and slider event in procedures is very nice and I will do it if my app works.

I reduced the debugging in the sketch to only print the handshake character and the app to only show a changing yellow point to see if the timer event works.



--
Let me try to answer your questions.

The problem with sending and receiving data in the same timer event is that if the Arduino is slow in responding, then the reading of the data gets stuck. Besides, I do not see any advantage in *sending* data withing a timer event.
Example: you move the blue slider, and the ledStripe or whatever it is, needs to do something. So, you could sent something like '<123B>' (the thumb position and a B, enclosed in square brackets. in one string and when the Arduino sketch is ready procession that, it could send an acknowledgement, maybe simply 'a'. By the way, it would be easier to process <B123> at the Arduino side, because you cannot be sure how many digits the thumbposition has, but if you position them the other way around, you can read until the > and convert the digits to an integer, and use it in your command to the leds.

Before you send the next command you should wait until an acknowledgement is received in your phone by the app. Yes, in the timer event. But you should always use BytesAvailableToReceive and not 1 or 2 or any other number. And, if your sketch is in debug mode it will send things like println('s'), which is 2 bytes, because of the line-end charcter that is included. Actually, you could use -1 as the nuber of bytes to recieve, and it will read until the next line-end, I believe, but it is less clear what is happening.

The chance that you will send a next command before you have received an acknowledgement is very slim, because human fingers are not fast enough, but you could use your globals to prevent sending a new command until an acknowledgement is received.

I do not think that the MIT APP Inventor team will give you another answer than I did above. You cannot serialize things that should be executed in parallel, and yes, the bluetooth read hangs if it cannot complete for some reason, but that has nothing to do with the timer event, only with the fact that the sketch is not able to respond in time, or responds with something you do not expect (like more bytes, or not an a or s).

I hope that it is more clear now what to do. I think my app is quite allright (except for the testing for acknowledgement), but your sketch is not yet. It would take me too much time right now to look at it and it is difficult, because I cannot test it. By the way, there exist apps and also PC terminal programs that you can use to debug your app. You can send commands that you type in a terminal setup and see the responses.
In fact it would be pretty easy to make one in AI2.

--
I will try to improve my app and my sketch with your advice.
But this will need some time because I can not work on it all the time.
I will tell about the results.
--
Take your time. It is your project. If you have questions, ask.

--

댓글 없음:

댓글 쓰기