Управление WEB-камерой

ourlive
Offline
Зарегистрирован: 26.05.2012

Пришли мне наконец то несколько сервоприводов, решил из них что нибудь соорудить для тренировки, т.к. ни разу не пользовался. Решил соорудить привод для вебки, которым можно будет порулить удалённо.

код mega2560:

#include <Servo.h> 
Servo servo1;
Servo servo2;
String bufer="";
int pos_servo = 5;

void setup() {
  Serial.begin(9600);        //установка скорости порта  
  Serial.println("mega_started");
  
  servo1.attach(9); //серва на D9
  servo2.attach(10); //серва на D10
//  servo1.write(1); delay(800); servo2.write(1); delay(800);  //тест крайних положений
//  servo1.write(179); delay(800); servo2.write(179); delay(800);
//  servo1.write(1); delay(800);
  
  servo1.write(90);                               // установка горизонтального положения
  servo2.write(90);
}

void loop()
{
  if (Serial.available() > 0) {
  char ByteRead=Serial.read();                    //чтение данных с порта
   if (ByteRead==char(13)) {                      //окончание строки
   convert_read();                                //передача данных на обработку
   bufer="";}                                     //лсвобождение буфера
   else {bufer=bufer+char(ByteRead);}             ///накопление данных в буфер
  }
}

/* #ping - => #pM001 - ответ
   #M<xxxyyy  (xxx;yyy) 0-1000 единиц, соответствуют 0-180 градусов
   #M>   
   
   библиотека сервы 0-100% положения выполняет как 0-180 радусов
   для SG5010 максимальный угол 120 градусов, 120гр фактические получаются командой  servo1.write(180);
   для исключения путаници угол поворота переводится в У.Е, в интервале 0-1000
*/

void convert_read() {
  if ((bufer.length()>3) && (bufer.substring(0,1)=="#")) {
    if (bufer.substring(1,5)=="png") {Serial.println("#pM001");}    //ответ на пинг
    if (bufer.substring(1,3)=="M<") {                               //получение координат
      int x=((int(bufer.charAt(3))-48)*100+(int(bufer.charAt(4))-48)*10+int(bufer.charAt(5))-48)*9/50; //выделение соответствующих байт (char(48)='0')
      int y=((int(bufer.charAt(6))-48)*100+(int(bufer.charAt(7))-48)*10+int(bufer.charAt(8))-48)*9/50; //и преобразование их в соответствующее значение
      if (y>178) {y=178;} //аппаратный косяк этой сервы (ограничение крайнего положения)
        servo1.write(y);
        servo2.write(180-x); 
//    Serial.print("x=");
//    Serial.print(180-servo2.read());
//    Serial.print(" y=");
//    Serial.println(servo1.read());
    } //#M<
  }
}

 

код processing:

import processing.serial.*;
Serial myPort;  


float rX, rY; //коэффициент вращения
float rX2, rY2; //коэффициент вращения, повторитель
boolean key_repeater=false;  //разрешение для повторителя
boolean key_animated=false;  //аключение анимации
float rX_max, rY_max, rX_min, rY_min; //границы вращения вращения
String port[];
String comport="";                //ком порт #pM001
String com_bufer="";              //буфер данных чтения компорта

void setup() {
size(600, 300, P3D);
background(0,0,0);                      // цвет фона
rX_max=1.3;                            // (-PI;PI) максимальные значения
rX_min=-1.3;
rY_max=1.3;
rY_min=-1.3;
}





void draw() {
draw_start();
text(comport+"   "+year()+"."+month()+"."+day()+" "+hour()+":"+minute()+":"+second(), 10, 30);

if (key_animated) {servo_animated();} else {com_select();}
} //*******************draw()

void draw_start() {                     //выполнять при каждой перерисовке (чтоб косяки не ловить)
clear();                                //очистить экран
textSize(18);                           //размер шрифта
fill(255, 255, 255);                    //цвет текста
stroke(255,255,255);                    //цвет линии
noFill();                               //не заливать фигуры
} //*******************draw_start()

void mousePressed() {
  if ((mouseButton == LEFT) && (key_animated)) {
   key_repeater= !key_repeater;                        //вкл.откл повторителя
  }
 
} //*******************mousePressed()

void servo_animated() {
  rX=float(mouseX)/(width-1)*PI*2-PI; //коэффициент вращения
  rY=float(mouseY)/(height-1)*PI*2-PI;
  if (rX<rX_min) {rX=rX_min;}
  if (rX>rX_max) {rX=rX_max;}
  if (rY<rY_min) {rY=rY_min;}
  if (rY>rY_max) {rY=rY_max;}
text((rX+PI/2) + " "+(rY+PI/2)+ " ", 10, 50);

//***********************************указатель
pushMatrix();                //начало контроля смещений

translate(width/2-100, height/2+50,0);  //смещение координат
box(70, 80, 40);             //1-привод
translate(-60,-30,0);
rotateX(rY);
box(40, 80, 70);             //2-привод
translate(10, -60,-40);
rotateY(-rX);
stroke(0,255,0);   
box(120, 5, 60);             //площадка
translate(0, -10,-100);
box(10, 10, -200);           //указатель
popMatrix();                //сброс смещений

//***********************************повторитель
pushMatrix();

fill(50,50,50);
translate(width/2+150, height/2+50,0);  //смещение координат для "ящика"
stroke(255,0,0);
box(70, 80, 40);             //1-привод
translate(-60,-30,0);
rotateX(rY2);
box(40, 80, 70);             //2-привод
translate(10, -60,-40);
rotateY(-rX2);   
box(120, 5, 60);             //площадка
translate(0, -10,-100);  
box(10, 10, -200);           //указатель
popMatrix();
if (key_repeater) {          //повторитель включен
  if (rX2<rX) {rX2=rX2+0.1;}
  if (rX2>rX) {rX2=rX2-0.1;}
  if (rY2<rY) {rY2=rY2+0.1;}
  if (rY2>rY) {rY2=rY2-0.1;}
        myPort.write('#'); //данные в серву
        myPort.write('M');
        myPort.write('<');
  int x=round((rX2+PI/2)*1000/PI);
  int y=round((rY2+PI/2)*1000/PI);
    int c=round(x/100);
    int d=round(x/10)-c*10;;
    int e=round(x)-c*100-d*10;
        myPort.write(char(c+48));myPort.write(char(d+48));myPort.write(char(e+48));
        c=round(y/100);
        d=round(y/10)-c*10;
        e=round(y)-c*100-d*10;
        myPort.write(char(c+48));myPort.write(char(d+48));myPort.write(char(e+48));
        myPort.write(char(13));
}  //****повторитель включен

}//*******************servo_animated()



void com_select() {                        //поиск нужного компорта
  String port[] = Serial.list();
  if (comport=="") {   
  int i = 0;
  while (i < port.length) {
    print("scan ");
    println(i);
  text(port[i],10,50+i*20);
  try { myPort = new Serial(this, Serial.list()[i], 9600);
        pause(1000);  //без паузы глючит и ком зависает
        com_read(); com_bufer=""; //опустошить буфер перед пингом
        myPort.write('#'); //пингануть
        myPort.write('p');
        myPort.write('n');
        myPort.write('g');
        myPort.write(char(13));
        pause(1000);
        com_read();       //прочитать данные
        if (com_bufer.substring(0,6).equals("#pM001")==true) {comport=port[i]; println("port "+port[i]+" OK"); i=port.length+1;  key_animated = !key_animated; } //если ответ правильный
        else {println("port "+port[i]+" NO OK");i++;  myPort.stop(); pause(1000); } //если ответ не правильный или его нет
  } catch (Exception e) {println(port[i]+" -");myPort.stop(); i++; } //данный порт не доступен, не отвечает или высылает неверный ответ
 
 
   
  }//***while
    
  }
} //************************************com_select()

void com_read() {                          //чтение данных из открытого порта
  while (myPort.available() > 0) {
    com_bufer = com_bufer + myPort.readString(); }
//  if (com_bufer != null) {println(com_bufer);}
}


//пауза выполнения скетча в миллисекундах
void pause(int ms) {long time=millis(); while (time+ms > millis()) {ms=ms;}}

public void stop(){  // ****************безопасная остановка(не работает)
  myPort.stop();
  super.stop();
}

картинки тут: http://yadi.sk/d/i3QuBmwYAA2Pe

Может кому то сгодятся отдельные решения. Например долго бился над проблемой автоматического выбора com-порта, вроде бы всё элементарно.. Ан нет, порт умудряется зависать как на ардуине, так и на jave, от чего процессинг его теряет. Также для меня оказалось открытием, что процессинг не может адекватно писать произвольные данные в Serial как та же ардуина, а только по одному байту, плюс непонятные проблемы с буфером, длинные строки данных от чего то обрезались (буду ещё разбираться). Некоторые неудобства доставила библиотека на серву для дуины, ей подавай данные 0-180 градусов, а мои сервы способны вращаться только в пределах 0-120, от чего пришлось вводить дополнительное преобразование в условные единицы, что бы избежать путанницы при использовании той же оболочки процессинга при других сервах.

На нижнюю серву приклеена гайка от фотика для установки конструкции на штатив. Остальное видно на картинках.

 

Сейчас всё работает более менее стабильно. И работает так: Включаем прошитую мегу с дополнительным питанием (для удобства распаяна панелька разъёмов, +5, GRN, D9, D10; на +5 и GRN зацеплен дополнительный источник, зарядка от старой мобилки), сервы eстанавливаются в среднее (горизонтальное) положение. Запускаем скетч процессинга. Он стартует и начинает скан портов, открывая поочерёдно каждый и отправляя пинги, мега получив пигн-команду отсылает ответ, процессинг с ответившим портом продолжает работу. После обнаружения порта отображается графическая имитация сервоприводов с вебкой. Дёргая мышкой в окне можно менять положение условных сервоприводов, левый клик в окно включает или отключает повторитель. При включенном повторителе данные непрерывно отсылаются в мегу.

На компе установлены Webcam Surveyor и TeamViever. Первый работает с камерой, второй обеспечивает удалённое управление компом. Ответная часть Тимвьювера стоит на мобилке, сообветственно подёргать курсором можно с любой точки планеты, а с ним и вебкой и полгядеть, чего же вебка показывает.

trembo
trembo аватар
Offline
Зарегистрирован: 08.04.2011

http://arduino.cc/en/Reference/ServoAttach

servo.attach(pin, min, max)

min (optional): the pulse width, in microseconds, corresponding to the minimum (0-degree) angle on the servo (defaults to 544)

max (optional): the pulse width, in microseconds, corresponding to the maximum (180-degree) angle on the servo (defaults to 2400)

И всё проблеммы решены.....

ourlive
Offline
Зарегистрирован: 26.05.2012

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