Управление сервами с геймпада


Захотелось сделать что-то большое и интересное. Ардуина при мне, да пара серв имеется — смело в бой!
Всё большое начинается с малого и первым делом решил я попробовать поуправлять сервами, а для удобства управления геймпад приспособить.
Первым делом скетч для ардуины изготовил. Использовал библиотеку Servo и нехитрый код, который распознаёт получение строки на COM-порт (не более 200 символов).

#include <Servo.h>

Servo myservo1;
Servo myservo2;

byte pos1 = 90;
byte pos2 = 90;

String inputString = "";
boolean stringComplete = false;

void setup()
{
  myservo1.attach(9);
  myservo2.attach(8);
  Serial.begin(9600);
  inputString.reserve(200);
}

void loop()
{
  if (stringComplete) {
    pos1 = inputString[0];
    pos2 = inputString[1];
    myservo1.write(pos1);
    myservo2.write(pos2);
    delay(15);
    inputString = "";
    stringComplete = false;
  }
}

void serialEvent() {
  while (Serial.available()) {
    char inChar = (char)Serial.read();
    inputString += inChar;
    if (inChar == '\n') {
      stringComplete = true;
    }
  }
}

Передаваемая строка должна иметь формат: <байт угла для первой сервы><байт угла для второй сервы><символ конца строки "\n">. Значения, полученные в виде байтов определяют угол поворота, на который будут повёрнуты сервы. На этом этапе сервами можно управлять из «Serial Mоnitor» Arduino IDE. Надо только не забыть установить в окне монитора обработку строк «Newline».

Управлять сервами из консоли не интересно. Захотелось большего! Можно конечно использовать для этого мышь или клавиатуру, но кажется более разумным использовать геймпад. Хочется, оно конечно хочется, но как обработку данных с геймпада организовать? Можно на C# программу написать, можно ещё что-то поэксплуатировать, но нашел я, что народ для подобной обработки Processing использует (с библиотекой procontroll).

В результате получился вот такой скетч процессинга:

import processing.serial.*;
import procontroll.*;
import java.io.*;

Serial myPort;
PFont fontA;

ControllIO controll;
ControllDevice device;
ControllSlider sliderX;
ControllSlider sliderY;

byte mX;
byte mY;

void setup()
{
  size(180, 180);
  String portName = Serial.list()[1];
  myPort = new Serial(this, portName, 9600);

  fontA = loadFont("Ziggurat-HTF-Black-32.vlw");
  textFont(fontA, 32);

  controll = ControllIO.getInstance(this);
  device = controll.getDevice("USB Gamepad ");
  device.setTolerance(0.05f);
  sliderX = device.getSlider(0);
  sliderY = device.getSlider(1);
}

void draw() {
  background(255);
  mX = byte(sliderX.getTotalValue());
  mY = byte(sliderY.getTotalValue());
  myPort.write(mX);
  myPort.write(mY);
  myPort.write("\n");
  fill(0);
  text(mX, 30, 60);
  fill(0);
  text(mY, 30, 120);
}

Пробуем! — Работает!!! 🙂

Дальше будем пробовать сделать из устройства что-то большее.


0 комментариев на «“Управление сервами с геймпада”»

    • Скачать библиотеку можно отсюда: creativecomputing.cc/p5libs/procontroll/. Как её установить зависит от версии процессинга, с которым вы собираетесь её использовать. Если требуется — я опишу как произвести установку.

      Я могу подробно описать и об особенностях подключения данной сервы к ардуинине и о том как работать с Arduino через COM-порт и скетчи прокомментировать. Укажите с какими трудностями Вы столкнулись и я постараюсь более бодробно остановиться на том, что непонятно.

  1. Компилятор Ардуино ругается на String inputString = "" пишет error: ‘String’ does not name a type In function ‘void setup()’:
    In function ‘void loop()’:
    In function ‘void serialEvent()’:
    а Processing на шрифт: Невозможно загрузить шрифт «Ziggurat-HTF-Black-32.vlw»

    • Со шрифтом разобрался. Надо было его просто добавить в процессинг самому. Tool -> create font и добавить Ziggurat-HTF-Black-32 в строку Filename. По крайней мере сработало. Теперь ругается на «USB Gamepad ». У меня называется Logitech Extreme 3D — штурвал самолета

    • Обратите внимание, что моё устройство называется «USB Gamepad » (с пробелом на конце!!! — видать глюк разработчиков). Посмотреть, как действительно называется Ваше устройство, можно использовав примеры к procontroll (уж не помню какие именно). Там, помнится, пример был, который выводил названия всех устройств и клавиш для них, которые вообще системой видятся (клавиатура, мышь, штурвал, …).

    • Также обращаю внимание на то, что «сервы» в моём примере инициализированы значениями по умолчанию. Т.е. при вызове «myservo1.write(pos1);», когда pos1=0 серва постарается повернуться к нулевому углу и возможно начнёт жужжать. Произойдёт это из-за того, что выдаваемые ардуиной управляющие импульсы будут короче тех, которые минимально возможны по документации сервы (это плохо для сервы). Вам необходимо изучить документацию к серве и грамотно инициализировать её управление в ардуино.

    • С джойстиком разобрался. Действительно пробел там лишний :). При компиляции вышла еще одна ошибка: ArrayIndexOutOfBoundsException 1 в строке String portName = Serial.list()[1]; [1] изменил на [0] и в окошке стали появляться координаты джойстика 🙂 А пример который определяет все подключенные устройства называется procontrol_printDevice.

    • Я бы теперь хотел сделать так чтобы при возврате джойстика в центральное положение сервы тоже возвращались в центральное положение. Пока не могу разобраться. Опыта маловато 🙁

    • С ошибкой в ардуино тоже разобрался. Использовал версию 1.0.1

    • Теперь заработало, но как-то странно:
      если джойстиком повернуть до упора серву на 180°, то она потом обратно на 0° возвращается сама и так пока не отпустишь джойстик. В processing-е при этом бегут числа от 0 до 127, а потом сразу от -127 до 0 и так по кругу.

    • Тут всё печально :(((((((((((( Дело в несовместимости форматов передачи данных. Конкретнее в передаче знаковых и беззнаковых переменных. Дело в том, что переменные можно разделить на знаковые и беззнаковые — те, которые хранят только положительные числа, и те, которые могут ещё и отрицательные хранить. При этом не стоит забывать про разрядность (количество бит на одну переменную), которая у обоих переменных может быть одинакова. Объясню на примере двух типов переменных, которые можно использовать в MS Visual Studio: int8 и uint8. Первая переменная может содержать числа от -127 до 128, вторая от 0 до 255. У обоих для хранения числа (тут я могу ошибаться, но смысл верен — см. справку для MS Visual Studio) используется 8 бит, но у первой первый бит хранит не число, а признак является ли число отрицательным. Так вот, ардуинина считает, что ей приходит беззнаковое число, а процессинг работает со знаковым. Отсюда такое непонимание, каково собственно положение джойстика должно быть.

    • Тут всё печально :(((((((((((( Дело в несовместимости форматов передачи данных. Конкретнее в передаче знаковых и беззнаковых переменных. Дело в том, что переменные можно разделить на знаковые и беззнаковые — те, которые хранят только положительные числа, и те, которые могут ещё и отрицательные хранить. При этом не стоит забывать про разрядность (количество бит на одну переменную), которая у обоих переменных может быть одинакова. Объясню на примере двух типов переменных, которые можно использовать в MS Visual Studio: int8 и uint8. Первая переменная может содержать числа от -127 до 128, вторая от 0 до 255. У обоих для хранения числа (тут я могу ошибаться, но смысл верен — см. справку для MS Visual Studio) используется 8 бит, но у первой первый бит хранит не число, а признак является ли число отрицательным. Так вот, ардуинина считает, что ей приходит беззнаковое число, а процессинг работает со знаковым. Отсюда такое непонимание, каково собственно положение джойстика должно быть.

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

      Я бы теперь хотел сделать так чтобы при возврате джойстика в центральное положение сервы тоже возвращались в центральное положение.

      — самому интересно такое реализовать. Если вы пришлёте мне код, который сейчас Вами написан, а также укажете модель серв, которые используете — я мог бы попробовать написать программку, которая Вашу задачу решает. Там, скорее всего, потребуется добавить в программу таймер (например, на 0,250 секунды) и при срабатывании таймера отправлять ардуинене не значение сдвига джойстика, а значение, на сколько данный сдвиг изменился.

    • Подскажите, пожалуйста, что в конечном счёте собрать хотите?

    • Да задача стоит в некотором смысле обычная: сделать поворотный механизм для камеры (или еще для чего-нибудь). Скетч скопировал полностью у Вас. Изменил только название джойстика и СОМ-порт. Единственное только смог добавить ось Z в Processing.

  2. примет я совсем не разбирусь как изменить код для управления с клавиатуры чтобы было управление радиоуправляемой машинкой. Я эту тему уже 2 месяца изо дня в день ищу и наконец то нашел благодаря вам! Заранее спасибо!

Добавить комментарий

Arduino

Что такое Arduino?
Зачем мне Arduino?
Начало работы с Arduino
Для начинающих ардуинщиков
Радиодетали (точка входа для начинающих ардуинщиков)
Первые шаги с Arduino

Разделы

  1. Преимуществ нет, за исключением читабельности: тип bool обычно имеет размер 1 байт, как и uint8_t. Думаю, компилятор в обоих случаях…

  2. Добрый день! Я недавно начал изучать программирование под STM32 и ваши уроки просто бесценны! Хотел узнать зачем использовать переменную типа…

3D-печать AI Arduino Bluetooth CraftDuino DIY Google IDE iRobot Kinect LEGO OpenCV Open Source Python Raspberry Pi RoboCraft ROS swarm ИК автоматизация андроид балансировать бионика версия видео военный датчик дрон интерфейс камера кибервесна манипулятор машинное обучение наше нейронная сеть подводный пылесос работа распознавание робот робототехника светодиод сервомашинка собака управление ходить шаг за шагом шаговый двигатель шилд юмор

OpenCV
Робототехника
Будущее за бионическими роботами?
Нейронная сеть - введение