Ардуино случайным образом прекращает отправку данных на python по последовательному
Я хочу отправлять команды Arduino через последовательный USB из моей программы на python, и Arduino должен отправить обратно полученную команду, чтобы убедиться, что данные не были потеряны. Однако Arduino случайным образом прекращает отправку данных обратно. Для целей отладки я заставил встроенный светодиод мигать в функции цикла. Когда Arduino перестает отправлять данные, светодиод замедляет мигание (примерно 2-3 раза). Я попробовал это на Arduino Uno и Arduino Nano, чтобы убедиться, что плата не повреждена.
Вот мой код на Python, отвечающий за связь:
class Communication(ABC):
def __init__(self) -> None:
self.history: list = []
self.response_history: list = []
self.last_responses: dict = dict()
self.queue: collections.deque[str] = collections.deque()
self.is_sending: bool = False
self.command_recived_condition: threading.Condition = threading.Condition()
def append_commands(self, commands: str) -> None:
commands = map(lambda x: "c"+x, map(lambda x: x+";", filter(len, commands.split(";"))))
for command in commands:
self.queue.append(command)
def append_and_send(self, commands: str) -> None:
self.append_commands(commands)
if not self.is_sending:
self.sender: threading.Thread = threading.Thread(target=Communication.send_commands, args=(self, ))
self.sender.start()
@abstractmethod
def send_command(self, command: str) -> bool:
""" Sends command to the controller, waits for the response and tries again if command was not recived succesfully """
pass
@abstractmethod
def listen(self) -> None:
pass
@abstractmethod
def check_for_response(self, command: str) -> None:
pass
def send_commands(self):
self.is_sending = True
commands = self.queue
while len(commands) > 0:
command = commands.popleft()
self.send_command(command)
self.is_sending = False
class Serial_comunication(Communication):
def __init__(self, port: str) -> None:
super().__init__()
self.serialcom = serial.Serial(port, 4800)
self.listen()
time.sleep(0.1)
self.send_command("PING;")
time.sleep(0.1)
def listen(self) -> None:
def listen_util() -> None:
chars = []
while True:
if self.serialcom.inWaiting() > 0:
time.sleep(0.01)
try:
char: str = self.serialcom.read().decode()
except UnicodeDecodeError:
print("decoding err")
continue
print(char, end=" ")
if char[-1] == '#':
response_str = "".join(chars)
category, content = response_str.split("::")
self.last_responses[category] = content
self.response_history.append(response_str)
chars.clear()
print("\n", response_str)
if category == 'Info: recived':
with self.command_recived_condition:
self.command_recived_condition.notify()
else:
chars.append(char)
time.sleep(0.01)
self.listener = threading.Thread(target=listen_util)
self.listener.start()
def check_for_response(self, command: str) -> None:
print("check")
if self.last_responses.get('Info: recived') == command:
print('possitive')
return True
return False
def send_command(self, command: str) -> None:
while True:
time.sleep(0.1)
self.serialcom.write(command.encode())
print("sent", command)
with self.command_recived_condition:
self.command_recived_condition.wait()
print("waited")
if self.check_for_response(command.strip().strip(';')):
break
И мой код Arduino, отвечающий за связь:
#define INPUT_SIZE 50
char input[INPUT_SIZE + 1];
bool check_for_orders(Order& cmd, char *val, uint8_t& place)
{
if (Serial.available() > 0)
{
// Считывать ввод с последовательного до ; что означает, что команда завершена
size_t size = Serial.readBytesUntil(';', input, INPUT_SIZE);
input[size] = 0; // Add null terminator
Serial.print(F("Info: recived::"));
delay(10);
Serial.print(input);
Serial.print(F("#"));
Serial.flush();
// Проверьте, не пуста ли команда
if (input[0] != 0)
{
// синтаксис "порядок:шаблон:место: значение"
cmd = static_cast<Order>(atoi(strtok(((char*)input)+1, ":"))); // Get order numer and convert to enum
place = atoi(strtok(NULL, ":")); // Get place number from input (only 0 or 1 is allowed)
char *value = strtok(NULL, ":"); // Get value from second part of string
if (value == 0) // Если значение пустое, то синтаксис недопустим
{
return false;
}
// В противном случае скопируйте имя и значение заказа в c-строки из основной функции
strcpy(val, value);
free(value);
return true;
}
else // Вероятно, этого никогда не случится
{
return false;
}
}
return false;
}
Функция check_for_orders запускается при каждом запуске функции цикла.
Вот что напечатал python, когда я отправил следующие команды ["PING;", "c0:0:0", "c0:1:0; c15:0:100,600,20,2,0,200,255,170,255,200;"]
sent PING;
I n f o : r e c i v e d : : P I N G #
Info: recived::PING
waited
check
possitive
sent c0:0:0;
I n f o : r e c i v e d : : c 0 : 0 : 0 #
Info: recived::c0:0:0
waited
check
possitive
sent c0:1:0;
I n f o : r e c i v e d : : c 0 : 1 : 0 #
Info: recived::c0:1:0
waited
check
possitive
sent c15:0:100,600,20,2,0,200,255,170,255,200;
I n f o : r e c i v e d : : c 1 5 : 0 : 1 0 0 , 6 0 0 , 2 0 , 2 , 0 , 2 0 0 , 2 5 5 , 1 7 0 , 2 5 5 , 2 0 0 #
Info: recived::c15:0:100,600,20,2,0,200,255,170,255,200
waited
check
possitive
sent c1:0:1;
/* and it got stuck */
Кто-нибудь знает, почему что-то здесь застряло и/или как решить эту проблему?
@Wisien, 👍2
Обсуждение1 ответ
Я удалил free(значение)
- ошибку новичка - но это не полностью решило проблему (но снизило частоту возникновения).
Похоже, объявлять массив как char val[50]
и передавать его в функцию как char* val
было плохой идеей. Я изменил объявление массива на char *val = новый символ[50]
, и теперь, похоже, все работает нормально.
Отправка char* val
допустима до тех пор, пока: 1. вы не переполняете val
; 2. вы разрешаете последний байт для байта NULL; 3. " val " всегда заканчивается нулем, независимо от размера, или вы также отправляете его размер, @Binar Web
- Как использовать pyserial для написания двух отдельных сообщений?
- `time.sleep` в скрипте python чтение последовательного вывода вызывает неустойчивое поведение
- Потеря данных при последовательном считывании с помощью Arduino Nano
- Управление ардуино через python
- Загрузка Arduino Nano дает ошибку: avrdude: stk500_recv(): programmer is not responding
- Не удается связаться с ардуино с помощью python (Windows)
- В чем разница между библиотеками Software Serial? Какая из них совместима с Arduino Nano?
- Как отправить команду AT на sim800l с помощью SoftwareSerial
4800 бод (я думаю, это ваша скорость передачи данных) - это довольно зрелищно. В зависимости от того, как часто и сколько вы отправляете, вы можете легко перегрузить последовательный интерфейс. Вы пробовали использовать более высокий коэффициент бодрствования? И можете ли вы привести минимальный рабочий пример, который показывает ваш код? Я имею в виду полный рабочий код, но без какого-либо не относящегося к делу кода, и это все равно показывает вашу проблему., @chrisl
не " бесплатно(ценность)`, @Juraj