Запутался, ткните носом.

Тема в разделе "Arduino & Shields", создана пользователем AVD, 8 июн 2012.

  1. AVD

    AVD Нуб

    Делаю проект 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)
     
     
  2. AVD

    AVD Нуб

    Добавил видео о работе, так наглядней (еще в обработке, пару минут)



    продолжение:

     
  3. nailxx

    nailxx Официальный Нерд Администратор

    Подводные лодки — круть!

    Для управления я бы на вашем месте принял другую концепцию. Вы сейчас с компа по serial посылаете какой серве куда повернуться, а я бы посылал значения X и Y в сыром виде с джойстика и уже на Arduino делал из этого выводы какой серве, какой электронике что с этим делать. Ну да не в этом вопрос.

    Я правильно понимаю проблему: у вас всё ок, если джойстиком рулить эксклюзивно вперёд-назад, либо эксклюзивно влево-вправо, но всё плохо, если оси совмещаются? Тогда стоит запоминать в переменных обновления значений по осям так, чтобы всегда знать значения X и Y джойстика. Далее, у вас есть два канала: левый и правый, им нужно задавать скорость/положение в зависимости от этих величин. Конечное значение скорости/положения можно получить из текущего положения джойстика:

    leftChannel = max(-1, min(1, joyX + joyY))
    rightChannel = max(-1, min(1, joyX - joyY))

    Результат привести из диапазона [-1; 1] к нужному, по вкусу.
     
    AVD нравится это.
  4. AVD

    AVD Нуб

    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 гр. т.е. по отдельности все ок.
     
     
  5. nailxx

    nailxx Официальный Нерд Администратор

    Да не. Не то имел в виду. Сейчас вы по 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)
    Надеюсь, идея понятна
     
  6. NewBot

    NewBot Нуб

    Я тут наваял примерно такое же, только управление танком с видеокамерой торчащей из башни.
    Изначально был такой-же джойстик, потом купил дешевый геймпад - им оказалось проще и быстрее управлять(и больше осей). Стырил у буржуинов и доработал напильником код, где есть есть функция "управление двумя каналами"(будь то моторы или серво) одним стиком...
    Посмотри, может пригодится...
    з.ы. Код полностью рабочий, с пояснениями, но недопиленный по красоте и наворотам. Только отключи камеру и перекинь оси/кнопки на свой джой (займёт 3 минуты времени).
     

    Вложения: