Тест робота-манипулятора от SAGA robotics

К нам, в школу RobotX попал учебный робот-манипулятор от компании SAGA Robotics. Ну как, "попал", компания SAGA любезно предоставила нам его для занятий и проведения полноценного тестирования, за что ей большое спасибо!
Разработчик предлагает на первом этапе использовать систему блочного программирование MBlock, которая, на мой субъективный преподавательский взгляд не имеет ничего общего с программированием роботов.

Тест робота-манипулятора от SAGA robotics

Поэтому предлагаю вам другой подход, который может быть легко применен в множестве других проектов!

Итак, сердце данного робота - микроконтроллер STM32, который управляет механикой манипулятора и производит вычисления. Пользователю предоставлена Arduino с набором команд, однако загружать каждый раз скетч, и тем более реализовать какое-то внешнее управление, а я планирую активно использовать этот манипулятор в курсе по компьютерному зрению!

К великому сожалению, онлайн с этим манипулятором пока не поработать, а вот пройти онлайн курс по работе с компьютерным зрением - легко! Переходите по ссылке ниже!

А речь дальше пойдет о методе взаимодействия Python скрипта и Arduino. Это уже не первый, описанный метод. Еще больше в телеграм-канале.

Начнем с того, что к Arduino нужно подключиться, для этого используется библиотека pyserial.

import serial import serial.tools.list_ports import time def find_arduino_port(): ports = serial.tools.list_ports.comports() for port in ports: try: ser = serial.Serial(port.device, 115200, timeout=1) time.sleep(2) # Ждем, пока Arduino перезагрузится ser.flushInput() ser.write(b'PING\n') # Отправляем команду PING response = ser.readline().decode().strip() if response == 'PONG': print(f"Arduino обнаружена на {port.device}") return ser ser.close() except serial.SerialException: continue print("Arduino не найдена") return None ser = find_arduino_port() if ser is None: exit()

Данная функция, автоматически найдет нашу плату Arduino среди любого количества COM портов. При успешном открытии порта отправим в него PING, и если в ответ получили PONG, значит это плата наша!
Этот метод также позволит вам подключаться и работать одновременно с несколькими платами Arduino не путаясь в них каждый раз!

На стороне Arduino должна быть программа, которая умеет ловко отвечать на поставленные запросы:

void setup() { Serial.begin(115200); } void loop() { // Проверяем наличие данных в Serial if (Serial.available()) { // Читаем входящую строку String command = Serial.readStringUntil('\n'); processCommand(command); } } void processCommand(String command) { command.trim(); // Удаляем лишние пробелы if (command.equalsIgnoreCase("PING")) { Serial.println("PONG"); } else { Serial.println("ERROR: Unknown command"); } }

Теперь, когда подключение выполнено, в нужный момент достаточно передавать в Serial команду, и разбирать ее на стороне Arduino. В качестве примера рассмотрим управляющую команду для движения робота в заданные координаты:

def send_command(command): print("Получена команда:", command) if command.startswith("MOVE_TO"): command = transform_command(command) print("Преобразована в команду:", command) ser.write((command + '\n').encode()) while True: response = ser.readline().decode().strip() if response: print("Ответ от Arduino:", response) print() break else: time.sleep(0.1) send_command('MOVE_TO 300 200 150')

В Arduino необходимо такую команду принять, разобрать на составляющие ее компоненты и передать управление в STM32.

void setup() { Serial.begin(115200); } void loop() { // Проверяем наличие данных в Serial if (Serial.available()) { // Читаем входящую строку String command = Serial.readStringUntil('\n'); processCommand(command); } } void processCommand(String command) { command.trim(); // Удаляем лишние пробелы if (command.equalsIgnoreCase("PING")) { Serial.println("PONG"); } else if (command.startsWith("MOVE_TO")) { float x = 0, y = 0, z = 0; parseMoveToCommand(command, &x, &y, &z); SD.SendCommandAndWaitForCommandDoneResponse(SD.command.MoveTo(x, y, z)); // Отправляем обратно координаты Serial.print("OK "); } else { Serial.println("ERROR: Unknown command"); } } void parseMoveToCommand(String command, float* x, float* y, float* z) { int index = command.indexOf(' '); if (index == -1) { Serial.println("ERROR: Invalid MOVE_TO command"); return; } String params = command.substring(index + 1); int idx1 = params.indexOf(' '); int idx2 = params.indexOf(' ', idx1 + 1); if (idx1 == -1 || idx2 == -1) { Serial.println("ERROR: Invalid MOVE_TO parameters"); return; } String xStr = params.substring(0, idx1); String yStr = params.substring(idx1 + 1, idx2); String zStr = params.substring(idx2 + 1); *x = xStr.toFloat(); *y = yStr.toFloat(); *z = zStr.toFloat(); }

По аналогии, можно формировать любые управляющие команды не только для манипуляторов!

Удачи в разработке!
Подписывайтесь на телеграм-канал:

Начать дискуссию