Делаю проект ROV подводный аппарат. Управление с компьютера и джойстика через Python. Проблема следующая: нужно что бы два аналог. подключенных к регуляторам скорости работали с двух осей Х Y т.е. если ручка джоя вперед то двигатели работают в паре и если повернем допустим на лева, то один двигатель теряет обороты но не отключается. У меня получилось сделать но идут помехи, т.к. серва норовит встать под 90гр. прописано в коде Python, вот код ардуино: Код (Text): // Import the Arduino Servo library #include <Servo.h> // Create a Servo object for each servo Servo servo1; Servo servo2; Servo servo3; Servo servo4; // TO ADD SERVOS: // Servo servo5; // etc... // Common servo setup values int minPulse = 600; // minimum servo position, us (microseconds) int maxPulse = 2400; // maximum servo position, us // User input for servo and position int userInput[3]; // raw input from serial buffer, 3 bytes int startbyte; // start byte, begin reading input int servo; // which servo to pulse? int pos; // servo angle 0-180 int i; // iterator // LED on Pin 13 for digital on/off demo int ledPin = 13; int pinState = LOW; void setup() { // Attach each Servo object to a digital pin servo1.attach(2, minPulse, maxPulse); servo2.attach(3, minPulse, maxPulse); servo3.attach(4, minPulse, maxPulse); servo4.attach(5, minPulse, maxPulse); // TO ADD SERVOS: // servo5.attach(YOUR_PIN, minPulse, maxPulse); // etc... // LED on Pin 13 for digital on/off demo pinMode(ledPin, OUTPUT); // Open the serial connection, 9600 baud Serial.begin(9600); } void loop() { // Wait for serial input (min 3 bytes in buffer) if (Serial.available() > 2) { // Read the first byte startbyte = Serial.read(); // If it's really the startbyte (255) ... if (startbyte == 255) { // ... then get the next two bytes for (i=0;i<2;i++) { userInput = Serial.read(); } // First byte = servo to move?[/I] servo = userInput[0]; // Second byte = which position?[/I] pos = userInput[1]; // Packet error checking and recovery[/I] if (pos == 255) { servo = 255; } // Assign new position to appropriate servo switch (servo) { case 1: servo1.write(pos); // если добавим серва 2 и 4 то работает, но как только даем в лева или в право начинается суматоха т.к. серва стремится встать под 90 гр.[/I] case 2: servo2.write(pos); break; case 3: } } } } А вот код Python: Код (Text): # Allow for multiple joysticks joy = [] # Handle joystick event def handleJoyEvent(e): # Identify joystick axes and assign events if e.type == pygame.JOYAXISMOTION: axis = "unknown" if (e.dict['axis'] == 0): axis = "X" if (e.dict['axis'] == 1): axis = "Y" if (e.dict['axis'] == 2): axis = "Throttle" if (e.dict['axis'] == 3): axis = "Z" # Convert joystick value to servo position for each axis if (axis != "unknown"): str = "Axis: %s; Value: %f" % (axis, e.dict['value']) # Uncomment to display axis values: #output(str, e.dict['joy']) # X Axis if (axis == "X"): pos = e.dict['value'] # convert joystick position to servo increment, 0-180 move = round(pos * 90, 0) serv = int(90 + move) # and send to Arduino over serial connection servo.move(1, serv) # Y Axis if (axis == "Y"): pos = e.dict['value'] move = round(pos * 90, 0) serv = int(90 + move) servo.move(2, serv)
Подводные лодки — круть! Для управления я бы на вашем месте принял другую концепцию. Вы сейчас с компа по serial посылаете какой серве куда повернуться, а я бы посылал значения X и Y в сыром виде с джойстика и уже на Arduino делал из этого выводы какой серве, какой электронике что с этим делать. Ну да не в этом вопрос. Я правильно понимаю проблему: у вас всё ок, если джойстиком рулить эксклюзивно вперёд-назад, либо эксклюзивно влево-вправо, но всё плохо, если оси совмещаются? Тогда стоит запоминать в переменных обновления значений по осям так, чтобы всегда знать значения X и Y джойстика. Далее, у вас есть два канала: левый и правый, им нужно задавать скорость/положение в зависимости от этих величин. Конечное значение скорости/положения можно получить из текущего положения джойстика: leftChannel = max(-1, min(1, joyX + joyY)) rightChannel = max(-1, min(1, joyX - joyY)) Результат привести из диапазона [-1; 1] к нужному, по вкусу.
Nailxx, Спасибо за ответ. а я бы посылал значения X и Y в сыром виде с джойстика т.е. значения с потенциометров джойстика? а не будет ли потерь на 30-40 метровом проводе типа CAT-5, я такой вариант рассматривал но джойстик у меня с обраткой да и сын летает иногда, но если потерь не будет тогда да вариант №1 Как я понял из Вашего ответа: 1. Объявляю переменные leftChannel и rightChannel и присваиваю значение списанное с переменной- servo из которого вычисляю скорость\положение ?? и // Ось Х servo2.write( leftChannel ) Nailxx, к сожалению моих знаний не хватает, помогите с проектом, с меня причитается. Код (Text): void loop() { // ждем 3 байта if (Serial.available() > 2) { // первый байт startbyte = Serial.read(); // проверяем (255) ... if (startbyte == 255) { // следующие два бйта for (i=0;i<2;i++) { userInput[i] = Serial.read(); } // первый байт = серво перемещение servo = userInput[0]; // второй байт = положение pos = userInput[1]; // проверка ошибок if (pos == 255) { servo = 255; } // Новая позиция серво switch (servo) { // движение с перменной pos case 1: // Ось Х servo2.write(pos); // левый вперед, назад servo5.write(pos); // правый вперед,назад break; case 2: // Ось Y servo2.write(pos); // левый двигатель реверс( в Питоне поставил в реверс) servo5.write(pos); // правый двигатель вперед break; case 3: // Центральный мотор глубины servo3.write(pos); break; case 4: // Серва камеры servo4.write(pos); break; .. вот такая схема работает но ! как только задеваю ось X или Y серва пытается уйти в 90 гр. т.е. по отдельности все ок.
Да не. Не то имел в виду. Сейчас вы по serial передаёте «серва такая-то, становись в такой-то угол», а я бы передавал «джойстик теперь находится в положении: X такой-то, Y такой-то». И там и там сигнал цифровой — длина проводов не помеха. Код (Text): #define CMD_DIRECTION_UPDATE 0x01 void loop() { if (Serial.available() < 3) return; // Пусть 3 байта — это: // * название команды: обновление по поворотным моторам, // глубинным моторам, камеры и т.п. // * arg0 и arg1: аргументы, которые имеют смысл специфичный // для конкретной команды byte command = Serial.read(); byte arg0 = Serial.read(); byte arg1 = Serial.read(); switch (command) { case CMD_DIRECTION_UPDATE: updateDirectionMotors(arg0, arg1); break; case BLA_BLA_BLA: // другая ваша команда break; case LA_LA_LA: // и т.п. break; } } void updateDirectionMotors(int joyX, int joyY) { // центрируем значения, переводим из диапазона // [0; 255] -> [-90; 90] joyX = map(joyX, 0, 255, -90, 90); joyY = map(joyY, 0, 255, -90, 90); // расчитываем значения для серв int leftChannel = max(-90, min(90, joyX + joyY)) int rightChannel = max(-90, min(90, joyX - joyY)) // действуем myLeftServo.write(leftChannel + 90); myRightServo.write(rightChannel + 90); } Вам остаётся подправить код на Python так, чтобы при изменениях на джойстике, комп посылал Arduino 3 байта: 1: команда на обновление двигателей поворота 0—255: значение джойстика по X (с центром равным 127) 0-255: значение джойстика по Y (с центром равным 127) Надеюсь, идея понятна
Я тут наваял примерно такое же, только управление танком с видеокамерой торчащей из башни. Изначально был такой-же джойстик, потом купил дешевый геймпад - им оказалось проще и быстрее управлять(и больше осей). Стырил у буржуинов и доработал напильником код, где есть есть функция "управление двумя каналами"(будь то моторы или серво) одним стиком... Посмотри, может пригодится... з.ы. Код полностью рабочий, с пояснениями, но недопиленный по красоте и наворотам. Только отключи камеру и перекинь оси/кнопки на свой джой (займёт 3 минуты времени).