1

I'm trying to receive a string from an Arduino to a Raspberry Pi via a Bluetooth socket connection (RFCOMM). I'm using an HC-06 Bluetooth module, an Arduino UNO R3, and an RPi 4 Model B. For the most part, everything is working well --except the first two data samples. This is what my output generally looks like when I view it from the RPi terminal:

0.
06,21,0.01,64
0.06,21,0.01,64
0.06,21,0.01,64
0.06,21,0.01,64
0.06,21,0.01,64
0.06,21,0.01,64

Is there any way I can get the first two lines to show the data properly? This data is a singular string and I chose my buffer to be 32 bits, so I don't think buffer size is the issue. I had to add time.delay(4) in my Py script or else every sample of the data would look messed up. I've tried adjusting the time delay relentlessly, but I can't seem to get the first two samples to display correctly. Below is a bit of my Python code:

while 1:
try:
        received_data = bluetoothSocket.recv(24)
        formatted_data = received_data.decode("utf-8")
        print("Received Data: ", formatted_data)
        time.sleep(4)

except KeyboardInterrupt:
        print("keyboard interrupt detected")
        break
bluetoothSocket.close()
6
  • why do you say that it is a problem with first two samples? ... it looks like a problem with just one line
    – jsotola
    Jul 15 at 22:33
  • @jsotola You're correct. It's just the first sample being split into two lines. Jul 16 at 0:13
  • 2
    It could be some previous data being buffered by the HC-06 which finally gets to come through once the rfcomm port is opened. Nothing much you can do about that unless you create a bidirectional protocol to instigate the communication only once the port is opened and the receiving program is ready to receive.
    – Majenko
    Jul 16 at 9:55
  • 1
    @Majenko Is there any way on the receiving Py script that I can have the socket "hold on" to the incoming string until a certain event happens? I heard there may be a way to do this so that when "\n" is reached, everything will be released from the socket. Jul 16 at 16:38
  • 1
    @phosphorescent I don't know - that's Python. I don't use Python. Personally I would have the Arduino do nothing at all until your Python program requests data to be sent. That way there can be no buffering issues. Also yes, you should read data up to the \n and use that as the delimiting factor of your communication instead of assuming 24 bytes.
    – Majenko
    Jul 17 at 12:35
1

You might want to try sending the data in a packet delimited by unique characters, e.g. { and }, similar to the JSON format.

The NMEA GPS standard uses $ and '\n' to delimit messages.

Here is an Arduino non-blocking C++ algorithm which builds upon Majenko's readline() example to read a packet. It returns true when incoming data has been accumulated into a valid packet. It should be fairly straightforward to convert it to Python.

void setup()
{
    Serial.begin(115200);
    Serial.println(F("\n\nSerial Packet Test\n"));
    pinMode(LED_BUILTIN, OUTPUT);
}

void loop()
{
    const static unsigned int INTERVAL = 200;
    static unsigned long previous_timestamp = millis();
    unsigned long current_timestamp = millis();
    static bool led_state = false;

    if (current_timestamp - previous_timestamp >= INTERVAL)
    {
        led_state = !led_state;
        digitalWrite(LED_BUILTIN, led_state);
        previous_timestamp += INTERVAL;
    }

    static char packet[100];

    if (ReadPacket(Serial, packet, sizeof(packet)))
    {
        Serial.print(F("Received packet >"));
        Serial.print(packet);
        Serial.println(F("<"));
    }
}

bool ReadPacket(Stream& stream, char *const packet, const unsigned int SIZE)
{
    const char FIRST = '{';
    const char LAST = '}';
    static bool read_until_last = false;
    static unsigned int i = 0;
    char ch;

    if (stream.available())
    {
        ch = stream.read();

        if (ch == FIRST)
        {
            Serial.println(F("Received FIRST."));
            i = 0;
            packet[0] = ch;
            read_until_last = true;
            return false;
        }
        if (read_until_last)
        {
            i++;
            if (i > SIZE - 2)
            {
                Serial.println(F("Buffer overrun. Resetting to look for next packet."));
                i = 0;
                read_until_last = false;
                return false;
            }
            if (ch == LAST)
            {
                Serial.println(F("Received LAST."));
                packet[i++] = ch;
                packet[i] = 0;
                read_until_last = false;
                return true;
            }
            else
            {
                Serial.print(F("Received char >"));
                Serial.print(ch);
                Serial.println("<");
                packet[i] = ch;
                return false;
            }
        }
    }
    return false;
}
1

I don't know what the time.sleep(4) statement fixes, but you could try moving the to the top of the loop instead of the bottom, so it precedes the first read. At the bottom of the loop, it's first execution comes after the first read.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.