Пользователь
0,0
рейтинг
15 января 2012 в 14:02

Строим гусеничного Bluetooth-робота с камерой. Часть 3

В предыдущих сериях:
Часть 1
Часть 2
Ну что, все уже заказали запчасти и собрали роботов? Пора робота оживить.
Сегодня мы разберем программную начинку.
Вариант, который я предлагаю максимально прост. Не стоит ждать от него уникальных способностей. Его задача — просто ехать работать. Отказоустойчивость, плавность управления и дополнительные функции — это простор для творчества, который я оставляю каждому, чтобы не лишать этого удовольствия. Код весьма простой и оттого далеко не оптимальный и не защищенный и вообще не красивый. Если есть предложения по его улучшению — предлагайте свои варианты, прямо куски кода с пояснением зачем и почему так будет лучше.
Неконструктивная критика того, что сделано плохо — не особо нужна :) Я и так знаю про недостатки. А вот если что-то непонятно- спрашивайте, поясню.
Итак, поехали!


Разделим задачу на простые этапы:
Бортовой контроллер
  • Управление моторами гусениц для движения вперед/назад и поворотов
  • Управление сервоприводами камеры
  • Прием по bluetooth и исполнение команд движения и управления сервоприводами камеры

ПК/Ноутбук
  • Вычисление скорости моторов для задания направления движения
  • Передача управляющих пакетов по bluetooth
  • Подключение джойстика для удобства управления

Управление моторами гусениц для движения вперед/назад и поворотов


Поскольку у нас используется готовый MotorShield а не голый H-bridge или L293D/L298N, то ничего особенно сложного изобретать не придется. Мы вспользуемся библиотекой AFMotor. Если у вас Motorshield V3 и вам нужна шина SPI — возьмите модифицированный вариант.
Комментарии я по привычке чаще всего пишу по-английски, так проще и короче.
Объявляем переменные для управления моторами. к 4му порту подключен правый мотор, к 3му — левый.
AF_DCMotor rMotor(4);  //Right motor
AF_DCMotor lMotor(3);  //Left motor


в зависимости от заданного направления и скорости коммандуем моторам вращаться (для левого мотора):

      switch (lDirection){
        case 0:
          lMotor.run(RELEASE);
          break;
        case 1:
          lMotor.run(FORWARD);
          lMotor.setSpeed(lSpeed);
          break;
        case 2:
          lMotor.run(BACKWARD);
          lMotor.setSpeed(lSpeed);
          break;
      } 


Для правого мотора то же самое:

      switch (rDirection){
        case 0:
          rMotor.run(RELEASE);
          break;
        case 1:
          rMotor.run(FORWARD);
          rMotor.setSpeed(rSpeed);
          break;
        case 2:
          rMotor.run(BACKWARD);
          rMotor.setSpeed(rSpeed);
          break;
      }

lDirection (или rDirection) принимает значения:
0 — остановить мотор
1 — вращение вперед
2 — вращение назад.

Управление сервоприводами камеры


Для управления сервоприводами объявляем два объекта panServo(отвечает за вращение камеры) и tiltServo (отвечает за наклон). Так как сервопривод механический и поворачивается не моментально, то введем переменную для задержки, требуемой приводу для отработки команды на поворот (15 мсек вполне достаточно)
Servo panServo, tiltServo;
long interval = 15;    // interval at which to control servo
long previousMillis = 0;   
unsigned long currentMillis;


previousMillis и currentMillis используются для того, чтобы в цикле управления не ждать тупо, когда отработает серво. Проверяем — если со времени последней команды не прошло 15 мсек, то командовать сервой бесполезно — она еще занята.
Кусок, отвечающий за вращение камеры:
      //Rotate camera
      currentMillis = millis();
      if(currentMillis - previousMillis > interval) {
        previousMillis = currentMillis;
        if (lastPan!=pan) panServo.write(pan);	     // tell pan servo to go to position
        if (lastTilt!=tilt) tiltServo.write(tilt);   // tell tilt servo to go to position
        lastPan=pan;
        lastTilt=tilt;
      }

Прием по bluetooth и исполнение команд движения и управления сервоприводами камеры


Bluetooth модуль с точки зрения Arduino — просто последовательный (UART) порт.
Поэтому мы будем в цикле опрашивать проверять — пришло ли что-то от компьютера. Если в буфере что-то нашлось, то ищем в потоке начало пакета — байт $FF (крайние положения сервоприводов и значения скоростей двигателей 255 практически бесполезны — сервы упираются раньше, а скорость 250-255 не отличается, поэтому в потоке такое значение будет встречаться крайне редко и это позволит нам выловить начало пакета, можно увеличить надежность, усложнив алгоритм, но нам вполне хватит и этого).
Обнаружив заголовок, принимаем байт, в котором закодировано направление двигателей по 2 бита на двигатель. Затем считываем скорости двигателей — по 1 байту на двигатель (lSpeed, rSpeed) и положения сервоприводов камеры (pan, tilt).
  if (Serial.available()>0) {
    Header=Serial.read();
    //If header found then get and process Cmd
    if (Header==255){
      while(Serial.available()<5){};

      Direction=Serial.read();
      lSpeed=Serial.read();
      rSpeed=Serial.read();
      pan=Serial.read();
      tilt=Serial.read();

Дальше выделяем направления для правого и левого двигателей
      lDirection=Direction & 0x03;
      rDirection=(Direction & 0x0C) >> 2;

и если направление или скорость изменились с последней принятой команды, то устанавливаем скорости двигателей и вращаем камеру.
Вот и весь основной рабочий цикл:
void loop() {
  
  if (Serial.available()>0) {
    Header=Serial.read();
    //If header found then get and process Cmd
    if (Header==255){
      while(Serial.available()<5){};

      Direction=Serial.read();
      lSpeed=Serial.read();
      rSpeed=Serial.read();
      pan=Serial.read();
      tilt=Serial.read();
      
      lDirection=Direction & 0x03;
      rDirection=(Direction & 0x0C) >> 2;
      //Left
     if ((lastlDir!=lDirection) or (lastlSpeed!=lSpeed)){
      switch (lDirection){
        case 0:
          lMotor.run(RELEASE);
          break;
        case 1:
          lMotor.run(FORWARD);
          lMotor.setSpeed(lSpeed);
          break;
        case 2:
          lMotor.run(BACKWARD);
          lMotor.setSpeed(lSpeed);
          break;
      }
      lastlDir=lDirection;
      lastlSpeed=lSpeed;
     }

      //Right
     if ((lastrDir!=rDirection) or (lastrSpeed!=rSpeed)){
      switch (rDirection){
        case 0:
          rMotor.run(RELEASE);
          break;
        case 1:
          rMotor.run(FORWARD);
          rMotor.setSpeed(rSpeed);
          break;
        case 2:
          rMotor.run(BACKWARD);
          rMotor.setSpeed(rSpeed);
          break;
      }
      lastrDir=rDirection;
      lastrSpeed=rSpeed;
     }
      
      //Rotate camera
      currentMillis = millis();
      if(currentMillis - previousMillis > interval) {
        previousMillis = currentMillis; 
        if (lastPan!=pan) panServo.write(pan);			// tell pan servo to go to position
        if (lastTilt!=tilt) tiltServo.write(tilt);		// tell tilt servo to go to position
        lastPan=pan;
        lastTilt=tilt;
      }

    }
  }
}

Как видите, проще уже практически некуда :)
Скачать скетч можно со страницы проекта в Google code.

Исполнять команды мы шасси научили. Теперь надо научиться отправлять их.
Кому лень разбираться в программировании или неохота ставить Delphi, могут скачать скомпилированный вариант

(работает с джойстиком Logitech Extreme 3D Pro или китайским геймпэдом EasyTouch).
imageimage
С остальными идем дальше :)

Нам понадобится:
  • Delphi 2010 (можно и Delphi 7, просто пару строк подправить нужно в файле проекта)
  • Компонент TComPort из открытой ComPort Library (у меня установлена 4.11с)
  • Компоненты TjvHIDDevice, TjvHIDDeviceController из JEDI VCL. Я использую v3.38, вы можете скачать посвежее. Ставьте целиком, пригодится

Вычисление скорости моторов для задания направления движения


Движение вперед и назад сложностей не вызывает — просто задаем одинаковые скорости левого и правого моторово и одинаковое направление.
Для поворотов в движении вводим понятие Steer — значение отклонения от прямого движения. Скорости двигателей вычисляем для движения вперед и назад так:
  if Speed>0 then begin
    //Forward
    //Left/Right turn
    lSpeed:=Speed-Steer;
    rSpeed:=Speed+Steer;
    if lSpeed<0 then lSpeed:=0;
    if rSpeed<0 then rSpeed:=0;
    if lSpeed>MaxSpeed then lSpeed:=MaxSpeed;
    if rSpeed>MaxSpeed then rSpeed:=MaxSpeed;
  end else begin
    //Backward
    //Left/Right turn
    lSpeed:=Speed+Steer;
    rSpeed:=Speed-Steer;
    if lSpeed>0 then  lSpeed:=0;
    if rSpeed>0 then  rSpeed:=0;
    if lSpeed<(-MaxSpeed) then  lSpeed:=-MaxSpeed;
    if rSpeed<(-MaxSpeed) then  rSpeed:=-MaxSpeed;
  end;


То есть при движении вперед из скорости левого двигателя отклонение вычитаем, к скорости правого — прибавляем. Получается эффект подтормаживания одной из гусениц и шасси плавно поворачивает, не останавливаясь полностью. При движении назад знаки просто меняются.
Ну и проверяем, не вышла ли скорость за максимально допустимые значения. В частности, это пригодится тем, у кого питание моторов напряжением выше чем им положено — просто ограничьте максимальную скорость и моторы будут целы.
Примеры по управлению:
ехать вперед — направление обоим моторам «1», скорость одинаковую
ехать назад — направление обоим моторам «2», скорость одинаковую
для поворота в вдвижении влево/вправо задаем направление одинаковое, скорости разные. Поворачивает в сторону, скорость которой меньше.
для поворота на месте — скорость одинаковая, направление моторов разное — развернется вокруг центра.
остановка — обоим моторам направление «0»

Передача управляющих пакетов по bluetooth


При добавлении bluetooth модуля в ПК образуется 2 виртуальных COM порта — один входящий, один исходящий.
Для подключения к роботу нужно всего навсего открыть исходящий порт. Можно определить в списке портов в настройках bluetooth или методом перебора — при подключении к правильному программа не будет ругаться и светодиод на модуле перестает мигать — соединение установлено, можно считать, что мы подключены напрямую к роботу.
procedure TfTank.bConnectClick(Sender: TObject);
begin
  if Tank.Connected then begin
    Tank.Disconnect;
    bConnect.Caption:='Connect';
  end else begin
    Tank.Port:=cbPort.Text;
    Tank.Connect;
    bConnect.Caption:='Disconnect';
    MessageBeep(MB_ICONINFORMATION);
  end;

end;

Для удобства я написал небольшой класс TRCTank, который реализует все действия по связи с роботом.
  TRCTank=class
  private
    fPort:string;
    ComPort:TComPort;
    Cmd, lastCmd:TControlPacket;
    fConnected:Boolean;
    function isConnected: boolean;
  protected
  public
    constructor Create;
    destructor  Destroy;override;

    procedure   Connect;
    procedure   Disconnect;

    procedure   SendCommand(lDir,left, rDir, right, pan, tilt:Byte);

    property    Port:string read fPort write fPort;
    property    Connected:boolean read isConnected;
  end;

Connect и Disconnect по сути просто открывают/закрывают порт ну и проверяют, текущее состояние, чтобы не пытаться открыть открытый или закрыть закрытый порт.

Чтобы послать команду роботу формируем заголовок, который будет ловить робот (у нас байт с кодом 255). А затем записываем команды в том порядке, как их ждет робот. Получается такая структура
  TControlPacket=record
    Header,
    Direction,
    lSpeed,     //left motor speed
    rSpeed  :Byte;//right motor speed
    pan,
    tilt    :Byte; //Camera pan & tilt
  end;

В функции отправки команды единственный момент, который стоит упомянуть — упаковка направлений для обоих двигателей в один байт смещением на 2 бита. Остальное очевидно.
procedure TRCTank.SendCommand;
begin
  if not fConnected then Exit;

  Cmd.Header:=255;
  Cmd.Direction:=lDir + rDir shl 2;
  Cmd.lSpeed:=left;
  Cmd.rSpeed:=right;
  Cmd.pan:=pan;
  Cmd.tilt:=tilt;

  if (lastCmd.Direction=Cmd.Direction) and
    (lastCmd.lSpeed=Cmd.lSpeed) and
    (lastCmd.rSpeed=Cmd.rSpeed) and
    (lastCmd.pan=Cmd.pan) and
    (lastCmd.tilt=Cmd.tilt) then Exit;

  ComPort.Write(cmd, SizeOf(cmd));
  lastCmd:=Cmd;
end;


Подключение джойстика для удобства управления


К сожалению, документации по работе с HID устройствами толковой в интернете не так много. В итоге я перебрал кучу устаревших кодов, которые отправляют к работе еще через midi порт или рассматривают джойстики как устройство с 2мя осями и 4 кнопками. Меня такой вариант не устраивал. Информации по компоненту TjvJoystick вообще нигде не было, поэтому наткнулся я на него случайно. А жаль, к этому моменту я уже написал свой компонент :) Так что если не поленитесь разобраться, то можете воспользоваться готовым компонентом из JEDI VCL.
Я же работаю с HID устройством напрямую и анализирую Report от него побайтово. Зато доступны все оси джойстика (у EasyTouch их 4) и все кнопки (10-12 у моих джойстиков).
Работает это так: с помощью компонента TjvHIDDeviceController на форме мы получаем список HID устройств в системе и выводим в комбобокс. Выбранный девайс отдаем объекту класса TRjoystick вызовом SelectJoystickByID(VID, PID: Word); (Выбирается по VendorID и ProductID — их можно посмотреть например в диспетчере устройств системы).
Класс TRjoystick выполняет checkout, получая возможность принимать репорты от джойстика, расшифровывает значения, устанавливает свойства кнопок и осей и вызывает процедуру обработчика. В нашей программе обработчик выглядит так:

procedure TfTank.OnJoyData;
var
  Hat:THatPosition;
  CenterCamera:Boolean;
begin
  Hat:=hCenter;
  CenterCamera:=False;

  //Easy touch joystick
  if (joyPID=6) and (joyVID=121) then begin
    scrPitch.Position:=TREasyTouchJoystick(Joy).rZ;
    scrAileron.Position:=TREasyTouchJoystick(Joy).Z;
    scrRudder.Position:=TREasyTouchJoystick(Joy).X;
    scrThrottle.Position:=TREasyTouchJoystick(Joy).Y;
    cbFire.Checked:=TREasyTouchJoystick(Joy).Btn1;
    cbAltFire.Checked:=TREasyTouchJoystick(Joy).Btn10;
    Hat:=TREasyTouchJoystick(Joy).Hat;
    CenterCamera:=TREasyTouchJoystick(Joy).Btn2;


    Speed:=Round(((TREasyTouchJoystick(Joy).rZ)-127)*2);
    Steer:=Round((TREasyTouchJoystick(Joy).Z)-127)*2;
  end;

  //Logitech Extreme 3D Pro
  if (joyPID=49685) and (joyVID=1133) then begin
    scrPitch.Position:=TRLogitechExtreme(Joy).Pitch;
    scrAileron.Position:=TRLogitechExtreme(Joy).Aileron;
    scrRudder.Position:=TRLogitechExtreme(Joy).Rudder;
    scrThrottle.Position:=TRLogitechExtreme(Joy).Throttle;
    cbFire.Checked:=TRLogitechExtreme(Joy).Btn1;
    cbAltFire.Checked:=TRLogitechExtreme(Joy).Btn2;
    Hat:=TRLogitechExtreme(Joy).Hat;
    CenterCamera:=TRLogitechExtreme(Joy).Btn1;

    Speed:=(TRLogitechExtreme(Joy).Pitch div 8)-255;   //4096 to -256..256
    Steer:=(TRLogitechExtreme(Joy).Aileron div 4)-127; //1024 to -127..128
  end;

  ApplyDeadZone(Speed,DeadX);
  ApplyDeadZone(Steer,DeadY);
  if Speed>MaxSpeed then Speed:=MaxSpeed;
  if Speed<-MaxSpeed then Speed:=-MaxSpeed;
  if Speed>0 then begin
    //Forward
    //Left/Right turn
    lSpeed:=Speed-Steer;
    rSpeed:=Speed+Steer;
    if lSpeed<0 then lSpeed:=0;
    if rSpeed<0 then rSpeed:=0;
    if lSpeed>MaxSpeed then lSpeed:=MaxSpeed;
    if rSpeed>MaxSpeed then rSpeed:=MaxSpeed;
  end else begin
    //Backward
    //Left/Right turn
    lSpeed:=Speed+Steer;
    rSpeed:=Speed-Steer;
    if lSpeed>0 then  lSpeed:=0;
    if rSpeed>0 then  rSpeed:=0;
    if lSpeed<(-MaxSpeed) then  lSpeed:=-MaxSpeed;
    if rSpeed<(-MaxSpeed) then  rSpeed:=-MaxSpeed;
  end;

  scrLeft.Position:=-lSpeed;
  scrRight.Position:=-rSpeed;

  if (cbAltFire.Checked) and (bConnect.Caption='Connect') then bConnect.OnClick(Self);

  case Hat of
    hUp: Inc(Tilt);
    hUpRight:begin
        Inc(Tilt);Dec(pan);
      end;
    hRight: Dec(pan);
    hRightDown: begin
        Dec(Pan); Dec(tilt);
      end;
    hDown: Dec(Tilt);
    hLeftDown: begin
        Inc(pan);Dec(tilt);
      end;
    hLeft: Inc(pan);
    hLeftUp: begin
        Inc(pan);Inc(tilt);
      end;
    hCenter: if CenterCamera then begin
       pan:=panCenter;
       tilt:=tiltCenter;
    end;
  end;

  //Limit Pan&Tilt range
  if pan<minPan then pan:=minPan;
  if tilt<minTilt then tilt:=minTilt;
  if pan>maxPan then pan:=maxPan;
  if tilt>maxTilt then tilt:=maxTilt;


  //Show info
  lJoy.Caption:='S:'+IntToStr(Speed)+' D:'+InttoStr(Steer)+' L:'+InttoStr(lSpeed)+' R:'+InttoStr(rSpeed);
  lhat.Caption:=THatPosString[Integer(Hat)];
  //Show camera position on sliders
  scrPan.Position:=pan;
  scrTilt.Position:=tilt;

  //Send command to tank
  Command2Tank;
end;

Сначала приводим сырые значения координат осей к диапазону скоростей -256..256 и направлений -127..128.
Поскольку при линейном управлении на малых значениях скоростей моторам не хватит сил сдвинуть с места робота, то вводим небольшие мертвые зоны (опытным путем) — двигаться будет только начиная с некоторого значения скорости. (ApplyDeadZone(Speed,DeadX); ApplyDeadZone(Steer,DeadY);)
После того, как учли руль направления, проверяем, что скорости не вылезли за диапазон, показываем на форме ползунками наглядно скорости моторов.
Затем в зависимости от положения шляпы меняем направление камеры или центруем ее, также проверяем ограничения (сервы упираются механически обычно раньше, чем достигают цифровых пределов управления). отображаем положение камеры на другой паре ползунков, выводим скорости и отправляем команду танку.
procedure TfTank.Command2Tank;
begin
  lDir:=0;
  rDir:=0;

  //prepare rDir, lDir data based on tracks speed
  case  lSpeed of
   0:lDir:=0; //stop
   1..255:  lDir:=1; //forward
   -255..-1:lDir:=2; //backward
  end;

  case rSpeed of
   0:rDir:=0; //stop
   1..255:  rDir:=1; //forward
   -255..-1:rDir:=2; //backward
  end;

  Tank.SendCommand(lDir,Abs(lSpeed),rDir,Abs(rSpeed), pan, tilt);
end;


В коде есть еще различные эксперименты, куски, отвечающие за сохранение выбранных порта и джойстика, сохранение и загрузку пределов управления и центровки камеры, есть возможность вернуть управление не джойстиком, а непосредственно дергая за ползунки скорости и направления. Но это не касается основной задачи управления. Можете пользоваться кодом как вам больше нравится, даже можете «устроить BolgenOS» если захочется :)
Скачать исходники R BT RC Tank можно на сайте проекта в Google code.
Я попытался снять процесс управления от первого лица, но съемка экрана камерой — неблагодарное занятие, вышло довольно посредственно. Но общий смысл понятен.


P.S. вот прямо сейчас шасси разобрано для переделки, поэтому быстро проверить какие-то изменения в коде на железе не смогу. Но версия, доступная для скачивания вполне работоспособна, как видно на видео.
Andrew Kambaroff @RaJa
карма
164,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое

Комментарии (42)

  • +9
    удобно под диваном искать различные предметы/питомцев
    • –1
      За городом подглядывать за соседями удобно
    • +7
      У некоторых под диван лучше не заглядывать
    • +1
      Это если диван достаточно высокий или камеры не слишком высоко торчит :)
    • +2
      Еще бы умел приносить продукты из холодильника — цены бы не было.
      • 0
        Что мешает взять платформу побольше и поставить манипулятор? :) Танки есть по полметра размером, манипуляторы тоже готовые продаются, если лень собирать. самое сложное — найти холодильник, открыть и найти в нем то, что нужно :)
        • 0
          • 0
            Хорошая платформа, только стоимость ее зашкаливает. И жесткость руки с камерой невелика, хоть и алюминиевые трубки — трясет сильно при остановке шасси.
            • 0
              Стоимость да, многовато. Жёсткость для такого типа манипуляторов (с сервами в сочленениях) неплохая. Их все такие трясёт ибо плечо большое и масса немаленькая, из-за серв.
              • 0
                там нужно опору делать не на хлипкие оси серв, а нормальную скобу на подшипниках или оси, а сервой только вращать, тогда будет гораздо жестче. При таком бюджете как у них это вполне оправдано.
        • 0
          image
          • 0
            Этот манипулятор так себе, но в качестве базы или на поиграться пойдет. правда цены на него в районе 100 баксов
      • 0
        Ага, как же, люди стараются, делают, надеются, а в итоге роботы сами «бухать» просят ;-)

        www.youtube.com/watch?v=DI8Unifggms
  • 0
    Для видео рекомендую использовать программы типа Jing, Camtasia или любую другую программу для снятия скринкастов.
    • +1
      Jing вроде ничего, но я так понял он бесплатный до 5 минут. А есть что-то, что не требует установки? Редко пользуюсь таким софтом.
      • –1
        Ваш ролик покороче будет. Программка вообще полезная. Я ей часто скриншоты делаю. Программ подобных полно, даже бесплатные есть, но хороших мало.
        • 0
          Раньше как-то видеоуроков делать не приходилось, поэтому снял просто камерой. А скриншоты делаю с помощью FastStone Viewer или Snipping tool.
  • 0
    А откуда самого робота скачать можно? =)
    • +6
      с ebay.com и terraelectronica.ru неплохо качается, но там скачивание платное :) Ссылки в первой части.
      • 0
        Скорее бы отпуск, руки уже чешутся собрать что-нибудь свое. Хочется что-то похожее по функциональности, но при этом почти бесшумное.
  • +1
    С беспроводного контроллера PS3 управление было бы удобнее он уже с Bluetooth
    • 0
      Да, но управление игрой и окончится, а у меня задача программного управления.
    • 0
      с чего это вы взяли что ps3 геймпад с блютус?
      • 0
        Как минимум из википедии, как максимум, это один из вариантов подключения к компу
  • +1
    =) Большое спасибо вам за этот «Шаг за шагом» Когда у меня вырастет сын, я буду что-нибудь подобное делать вместе с ним, в плане обучения. Вы меня вдохновили.
    • +2
      Эх… А когда у меня вырастет сын, мы с ним будем собирать простейшие левитирующие 3D-сканеры, которые будут продаваться в наборах «для детей дошкольного возраста» :(
    • +1
      Большое пожалуйста, вот для тех, кто хочет научиться сам или научить детей я и писал :)
  • 0
    Вынашиваю идею сборки подобно, но пока что как основная проблема встает обработка команд с джойстика. Есть ли нормальные методы для работы с USB-HID устройствами? Возможна ли кросплатформенность управляющего ПО?
    • 0
      Ну вот сам же частично отвечу на свой вопрос robot-develop.org/archives/1537 Qt c выносом плат форменно-зависимого кода.
      • 0
        Не, изучать Qt у меня пока необходимости и желания нет, писать под Delphi быстрее и проще. Linux-машин с GUI у меня нет, да и не писал я под ним ни разу. Удобных средств RAD разрабтки под ним особо нет (Lazarus — тот еще уродец). Честно говоря кросс-платформенность меня совершенно не волнует :) Послать несколько байт можно с любого устройства, а логику пишите на чем вам удобнее. Я показал частный вариант реализации. Можно заменить bluetooth на WiFi, Xbee, RF. Гусеницы заменить на автомобильчик и результат все равно будет сходный. Джойстик можно использовать такой, какой есть под рукой, если он видится как HID устройство. Разобрать протокол — дело получаса максимум. Я себе написал простенькую программку, которая показывает идущие репорты от устройства. Да и в примерах у JEDI VCL есть проектик, который читает репорты.
    • 0
      Нормальные методы работы с HID устройствами есть. и под Win и под Linux. но под Linux я не писал. Под Windows я делаю как раз USB HID устройство для управления питанием колонок, настольной лампы и т.п.
  • +1
    Черт, я как раз купил джойстик на барахолке 1996 года, и именно так и хотел его использовать)
    Тоже хочется чтобы ездило, смотрело, лучше даже стреляло по кнопкам чем-нибудь, например пульками китайскими пластиковыми… и да, я не стану танкистом).
    Скоро будет и мой пост о сборке одного интересного устройства, примерно через полтора месяца)
    • 0
      Да, очень хочется еще к нему наводимую пулялку приделать и почувствовать себы оператором беспилотника на гусеницах. Если сделать два комплекта таких «танков» то можно очень нехилый миниполигон в квартире устроить, особенно если операторы будут видеть только изображение с камеры и ничего более.
      Можно еще распознавалки в компе подключить и устраивать бои роботов на полном автомате. Движуха может быть еще та.
  • 0
    А у меня был такой же ковер! (Хотя технически он все же «палас».)
  • 0
    Тоже делал однажды BT робота с камерой. Взял шасси от Mindstorms и камеру на основе андроида. Компоненты дорогие, зато простейшего робота можно собрать за час. Вот кому интересно: rai220.livejournal.com/153855.html
    • 0
      Забавно, конечно, но и вправду дорого. А проблема даже не в этом. Существенно расширить функционал будет крайне трудно, особенно в части управления с ПК — лаги что-то уж очень велики. А по цене проще купить китайский автомобильчик и поставить на него тот же телефон, если хочется просто порулить машинкой к видео :)
      • 0
        На самом деле лаги идут от камеры. Сама машинка реагирует очень бойко, хотя и дальности встроенного USB явно недостаточно для таких целей.
        • 0
          *встроенного BT
          • 0
            Да, интерфейс там особо не заменишь.
            • 0
              Можно использовать как раз USB. Собственно сейчас делаю проект, который позволяет управлять манипулятором через интернет. В виду того, что мой arduino застряла на почте, собираю из лего :) И вот подключил контроллер по usb и вообще никаких нареканий.
  • 0
    Эта камера не подходит для этого робота. У неё очень узкий FOV. Не удобно управлять по камере, плохо чувствуется скорость и расстояние. Для таких роботов нужны камеры с широким углом обзора.
  • 0
    Руководствуясь статьей собрал почти такого же робота: www.youtube.com/watch?v=EKOa53JaOAg. Мой управляется через Андроид-смартфон или через десктопный гуй.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.