Проблема с первыми двумя образцами последовательных данных, полученных RPi

Я пытаюсь получить строку от Arduino к Raspberry Pi через соединение с разъемом Bluetooth (RFCOMM). Я использую модуль Bluetooth HC-06, Arduino UNO R3 и RPi 4 модели B. По большей части все работает хорошо-за исключением первых двух образцов данных. Вот как обычно выглядит мой вывод, когда я просматриваю его с терминала RPi:

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

Есть ли какой-нибудь способ заставить первые две строки правильно отображать данные? Эти данные представляют собой единственную строку, и я выбрал свой буфер размером 32 бита, поэтому я не думаю, что проблема в размере буфера. Мне пришлось добавить время.delay(4) в моем сценарии Py, иначе каждый образец данных выглядел бы испорченным. Я пытался безжалостно регулировать временную задержку, но, похоже, не могу правильно отобразить первые два образца. Ниже приведен фрагмент моего кода на Python:

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()

, 👍1

Обсуждение

почему вы говорите, что это проблема с первыми двумя образцами? ... это похоже на проблему только с одной строкой, @jsotola

@jsotola, ты прав. Это всего лишь первый образец, разделенный на две строки., @phosphorescent

Это могут быть некоторые предыдущие данные, буферизованные HC-06, которые, наконец, поступают после открытия порта rfcomm. Вы ничего не можете с этим поделать, если только не создадите двунаправленный протокол для инициирования связи только после того, как порт открыт и принимающая программа готова к приему., @Majenko

@Majenko Есть ли какой-либо способ в получающем сценарии Py, чтобы сокет "удерживал" входящую строку до тех пор, пока не произойдет определенное событие? Я слышал, что может быть способ сделать это так, чтобы при достижении "\n" все было выпущено из сокета., @phosphorescent

@фосфоресцирующий Я не знаю - это Питон. Я не использую Python. Лично я бы попросил Arduino вообще ничего не делать, пока ваша программа на Python не запросит данные для отправки. Таким образом, не может быть никаких проблем с буферизацией. Кроме того, да, вы должны считывать данные с точностью до "\n " и использовать их в качестве разделяющего фактора при общении, вместо того, чтобы предполагать 24 байта., @Majenko

Простое исправление: сначала отправьте шаблон вместо того, чтобы сразу переходить к данным. Что-то вроде "--BEGIN--\n", которое вы можете легко удалить в python., @dandavis


2 ответа


1

Возможно, вы захотите попробовать отправить данные в пакете, разделенном уникальными символами, например { и}, аналогично формату JSON.

Стандарт GPS NMEA использует $ и '\n' для разделения сообщений.

Вот неблокирующий алгоритм Arduino на C++, который основан на примере readline() Майенко для чтения пакета. Он возвращает значение true, когда входящие данные были собраны в допустимый пакет. Преобразовать его в 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

Я не знаю, что исправляет оператор time.sleep(4), но вы можете попробовать переместить его в верхнюю часть цикла вместо нижней, чтобы он предшествовал первому чтению. В нижней части цикла первое выполнение происходит после первого чтения.

,