Передача данных в Arduino и с него на Raspberry Pi
Я пытаюсь передать данные акселерометра MPU6050 + данные с 3 потенциометров с Arduino на Raspberry Pi. Я выполняю постобработку здесь (на Raspberry Pi), а затем передаю данные обратно в Arduino для перемещения исполнительных механизмов. Однако моя проблема заключается в том, что когда я пытаюсь записать обработанные данные обратно в Arduino, я вижу, что даже поток входящих данных из Arduino начинает повреждаться, и все становится очень медленным. Даже если я просто считываю последовательные данные с Arduino, все происходит медленнее, чем если бы я выполнял обработку непосредственно на Arduino. Кроме того, данные акселерометра, похоже, перестают отвечать на запросы, т.Е. Их значение не меняется, если я перемещаю акселерометр. Все просто работает нормально, если вся обработка выполняется на Arduino. Я не знаю, что происходит не так. Ниже приведены мои функции / коды Arduino и Python.
Код Arduino:
void send_rec_data(){
Serial.print(Kp);
Serial.print(",");
Serial.print(Kd);
Serial.print(",");
Serial.print(Ki);
Serial.print(",");
Serial.println(Theta_x);
delay(20);
if (Serial.available()>0){ // Считывать данные, отправленные Raspberry Pi / Piserial
str_data = Serial.readString();
int firstCommaIndex = str_data.indexOf(',');
cmd = str_data.substring(0, firstCommaIndex); // Здесь хранится масштабированный вывод из Raspberry Pi
param1 = str_data.substring(firstCommaIndex+1); // Здесь сохраняется ошибка от Raspberry Pi для определения направления вращения двигателя
Output = cmd.toFloat(); my_error = param1.toFloat(); // Измените выходные данные со string на float
blink_led(); // Мигающие светодиоды, если данные получены от Raspberry Pi
}
}
Код на Python:
while 1:
data = cont.get_serial_data(arduino)
time.sleep(0.02)
if data is not None:
Kp, Kd, Ki, Theta_x = data
print(" \n Arduino sent Kp = ", Kp , "Kd = ",Kd , "Ki = ", Ki, "Theta_x = ", Theta_x)
cont.set_tunings(Kp, Kd, 0)
Output_scaled = cont.Compute_PID_Output(Input = Theta_x) # Compute the output of PID Algorithm
ff = str(Output_scaled)+','+str(cont.error)
arduino.write(ff.encode())
print("\n Computed data sent TO ARDUINO Output_scaled = ", Output_scaled, "Error = ", cont.error)
arduino.close()
Я потратил некоторое время на то, чтобы решить проблему, отключив задержки и очистив буфер, но пока ничего не получалось. Может кто-нибудь, пожалуйста, помочь.
Спасибо.
@Nischal, 👍0
Обсуждение2 ответа
Лучший ответ:
Спасибо вам всем. Я прочитал этот форум, и там также говорится о тех же вещах, которые вы, ребята, также предложили. Я сделал то же самое, и теперь все происходит быстро.
Serial.readString()
это действительно проблема.
Хорошо, не переписывая весь ваш код, одна вещь, которую я вижу здесь, - это множество строковых функций sloooow.
Например, функция печати Pythons работает чрезвычайно медленно. Вы должны вставить несколько таймеров в свой код и посмотреть, сколько времени все это займет. Я думаю, вы будете удивлены.
Для приложения реального времени, которое, похоже, таковым и является, вам нужно быть очень осторожным и использовать тайм-ауты и неблокирующий код, чтобы убедиться, что все неожиданно не остановится.
Вам действительно нужно переписать весь этот код заново, но я укажу на несколько конкретных проблем.
delay(20);
if (Serial.available()>0){
...
}
Это неаккуратно. Если ваш код python не обрабатывает и не возвращает данные до истечения 20 мс, все будет синхронизировано.
str_data = Serial.readString();
Взгляд на документацию показывает, что это будет возвращаться только по тайм-ауту, так что это гарантированно блокируется на 1 секунду (я думаю, это значение по умолчанию), так что есть еще одна проблема с остановкой показа. Смотрите Этот вопрос для получения дополнительной информации.
cmd = str_data.substring(0, firstCommaIndex);
Этого тоже недостаточно. Между pi и arduino нет синхронизации, поэтому у вас нет гарантии, что вы не получите половину предыдущей передачи, прикрепленной к передней части строки данных (или хуже). Вам нужно создать свой собственный буфер и выполнить синтаксический анализ для обработки данных. Или сделайте тщательную очистку буфера и используйте щедрые тайм-ауты.
Итак, TLDR; вот что вы хотите сделать (предполагая, что вы хотите заблокировать, пока происходит этот обмен)
- Очистите буфер приема arduino.
- Отправьте пакет данных с arduino.
- Начните получать. Добавьте полученные байты в буфер символов.
- Постоянно выполняйте поиск в этом буфере для вашего полного пакета данных.
- Тайм-аут после x мс. Как-то справьтесь с отсутствием возвращенных данных.
- Если вы все-таки найдете полный пакет данных, то обработайте его.
О Пи:
- Опрос для получения последовательных данных. Добавьте его в буфер по мере поступления.
- Начните удалять самые старые символы из буфера, если он длиннее в 2 раза самого длинного пакета данных
- Непрерывно выполняйте поиск в буфере вашего пакета данных. Если вы найдете его, то продолжайте ниже.
- удалите пакет данных из буфера приема.
- обработайте данные.
- Отправьте обратный пакет данных в arduino.
- Можно ли измерить скорость акселерометром? Насколько точно?
- В чем разница между акселерометром, гироскопом и датчиком магнитометра?
- OVF в последовательном мониторе вместо данных
- Как связаться с датчиком через порты RX/TX Arduino?
- Линейное ускорение от MPU 6050
- Как правильно определить крен, тангаж, перемещение?
- Правильный способ получить значения крена, тангажа и перемещения
- Снять гравитацию с акселерометра MPU-6050
Вам следует начать с серьезного обдумывания необходимых вам сроков общения: Сколько байтов вы хотите отправить в каждом направлении? С какой скоростью передачи данных? Как часто? Затем прочитайте [Моргайте без промедления] (https://www.arduino.cc/en/Tutorial/BlinkWithoutDelay ), просто чтобы узнать, как писать неблокирующий код, затем [Чтение серийного номера на Arduino] (https://hackingmajenkoblog.wordpress.com/2016/02/01/reading-serial-on-the-arduino /)., @Edgar Bonet