Hi, I am trying to receive the heart rate data from bluetooth as float values ( E.g. "65.60") every second and graph it for visual representation. While it seems like the receiving data from bluetooth works properly but the graphing is not. It just keeps crashing after every few second. There must be something wrong with my whole app flow. Please anyone help me take a look at it.
Check the tool tip for that ImportFromList block:
ImportFromList(list)
Imports the data from the specified list parameter to the data series. The list is expected to contain element which are also lists. Each list element is expected to have 2 values, the first one being the x value, and the second one being the y value. Invalid list entries are simply skipped. Existing data are not cleared.
You did two things wrong:
- You did not feed it a list of (x,y) pairs
- You did not Clear() the Data Series.
If you need coding help,
export and post the aia here.
Thank you very much. For the code, I want to try and figure it out myself first. I will ask if I am stuck again.
Here is a topic about using the bluetooth component and chart.
I wouldn't trust "Bytes available to receive" to the minute detail your code is - at the moment of verify it could be the correct total but a moment later a greater total. We would normally regard that block as a flag that tells us data is ready, then import all the data: numberOfBytes = -1.
Why do you need vary between 5 and 6 bytes?
You're absolutely right. Now, I'm having some issues on receiving data. The program is supposed to be receiving heart rate data, usually float values sent as strings. (E.g 74.34) But the issue is sometimes it accepts double the value (74.3473.23) like this. Then it will mess up the app. Any suggestions on how to fix that. By the way, I changed to specific bytes to bytesavailabletoreceive. But the problem exists even before that.
That can be done in the Sketch/Script before the data is sent, set the max decimal places when converting float to string.
Edit - if you are making such a conversion. It would be easier to help you if you uploaded your Script/Sketch.
Serial.print(floatNumber, decimal_places);
Here's the code. It converts the float value to string and transmit it via bluetooth. The clock interval is 1 second, and it only transmits when there're any new numerical changes. I thought about just sending it as float values, can it work? But if I just send float, it is 64 bits (according to my understanding) so it wouldn't work with my 8-bit transmitting function. For string, I send it as chunks of 8bit characters, so it works. Can you shed some light on that pls.
Also, I put 3 decimals instead of 2 so it can terminate on 0 value. But it also doesn't work properly, I thought it has something to do with delimiter, right? But I can't seem to figure it out.
Be sure to use println() at the end of each message to send from the sending device, to signal end of message.
Only use print() in the middle of a message.
Be sure not to println() in the middle of a message, or you will break it into two short messages and mess up the item count after you split the message in AI2.
Do not rely on timing for this, which is unreliable.
In the AI2 Designer, set the Delimiter attribute of the BlueTooth Client component to 10 to recognize the End of Line character.
Also, return data is not immediately available after sending a request,
you have to start a Clock Timer repeating and watch for its arrival in the Clock Timer event. The repeat rate of the Clock Timer should be faster than the transmission rate in the sending device, to not flood the AI2 buffers.
In your Clock Timer, you should check
Is the BlueTooth Client still Connected?
Is Bytes Available > 0?
IF Bytes Available > 0 THEN
set message var to BT.ReceiveText(-1)
This takes advantage of a special case in the ReceiveText block:
ReceiveText(numberOfBytes)
Receive text from the connected Bluetooth device. If numberOfBytes is less than 0, read until a delimiter byte value is received.
If you are sending multiple data values per message separated by | or comma, have your message split into a local or global variable for inspection before trying to select list items from it. Test if (length of list(split list result) >= expected list length) before doing any select list item operations, to avoid taking a long walk on a short pier. This bulletproofing is necessary in case your sending device sneaks in some commentary messages with the data values.
Some people send temperature and humidity in separate messages with distinctive prefixes like "t:" (for temperature) and "h:" (for humidity).
(That's YAML format.)
The AI2 Charts component can recognize these and graph them. See Bluetooth Client Polling Rate - #12 by ABG
To receive YAML format messages, test if the incoming message contains ':' . If true, split it at ':' into a list variable, and find the prefix in item 1 and the value in item 2.
I think just the wrong approach in there Iwan. The String represents only one float, is that right? If so, from a Bluetooth perspective it should be sent as one string. You are right about needing to tell the App where the end of the string is. That has to be defined in the script and in the App. We usually use ASCII char 10, Line Feed, '\n' in your script.
sprintf("%.2f\n",beatAvg);
Now, you may find that value should be sent to the App before sending it to the ST7735. If you are displaying the data within the App, is the ST7735 even necessary?
Finally, it has to be considered that occasional glitches can occur, so ensure the code on both sides has a way of getting out of trouble without crashing, even if that has to be a message asking the User to touch a button and reset.
However, we don't know anything about your hardware setup other than the ST7735. - what microcontroller are you using, is BT built in or are you using a BT module? Sensors?
I am using TM4C123GXL microcontroller, with MAX30102 heart sensor and HC-05 Bluetooth module. ST7735 is redundant, yes but I already have a ready code, so I included it.
The operation * cannot accept the arguments: , ["72.80 79.50 "], [1]
Note: You will not see another error reported for 5 seconds.
I tried adding new line for my transmission and set the delimiter to 10. But it just makes that there's a space between values in the error. I don't understand, it seems so simple to fix, but I couldn't get it.
Can you upload your Script file so we can have a proper look into it?
There should only be one value, but this is what you see on the App side? I'm thinking that maybe the data is arriving faster than 1 second between values.
Edit: Try a temporary timing change of, say, at least 5 seconds per value.
Also, increase the buffer size for sprintf() to 32
I somewhat "fixed" it by changing the clock polling in the app to 0.5 second while the clock from microcontroller stays at 1 second. For now, no error yet. I know it is not the proper solution, but I just want to skip to the next step. Thank you very much for the replies.
That could well be the Ultimate Fix - we didn't know you had both send and receive set the same, which if you think about it, cannot work as the App needs time to process the value - so the App process must complete before the next value is sent.