Строим гусеничного 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. вот прямо сейчас шасси разобрано для переделки, поэтому быстро проверить какие-то изменения в коде на железе не смогу. Но версия, доступная для скачивания вполне работоспособна, как видно на видео.
    Метки:
    Поделиться публикацией
    Похожие публикации
    Комментарии 42
    • +9
      удобно под диваном искать различные предметы/питомцев
      • –1
        За городом подглядывать за соседями удобно
        • +7
          У некоторых под диван лучше не заглядывать
          • +1
            Это если диван достаточно высокий или камеры не слишком высоко торчит :)
            • +2
              Еще бы умел приносить продукты из холодильника — цены бы не было.
              • 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. Мой управляется через Андроид-смартфон или через десктопный гуй.

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