Zpomalení serv s použitím driveru PCA9685

Dark
Příspěvky: 8
Registrován: 21 pro 2019, 21:37
Reputation: 0

Re: Zpomalení serv s použitím driveru PCA9685

Příspěvek od Dark » 23 pro 2019, 17:03

Aha, no tak proto :D Teď jsem ten program dostal do stejného stavu principielně, jako byl na začátku, akorát teď tam jsou jen ty dvě zmiňované fce, ještě budu muset nahradit globální proměnné atd., ale to už pořeším později. Takže toto je zkracený program, jenže když jsem to chtěl zpomalit, tak jsem se úplně zamotal v těch polích kterých tu je tedy požehnaně -_-

Kód: Vybrat vše

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>

Adafruit_PWMServoDriver driverPCA = Adafruit_PWMServoDriver(0x40);

#define tl1 11
#define tl2 12

const int CISEL=6;
const int POCET=20;

int m[CISEL][POCET];
int pos[CISEL], pulse[CISEL], predchozi[CISEL];
int pot[CISEL]={A0,A1,A2,A3,A6,A7};
int PWM_pin[CISEL]={0,1,2,3,4,5};
int posledniPoloha, p=0, i=0;

void setup() {
  driverPCA.begin();
  driverPCA.setPWMFreq(60);

  pinMode(tl1,INPUT);
  pinMode(tl2,INPUT);
}

void loop() {
  if(digitalRead(tl1)==HIGH){
    for (int i=0; i<CISEL; i++){
      m[i][p]=pos[i];
    }
p++;
delay(500);
}
  if(digitalRead(tl2)==HIGH){
   p=0;
  while(p<posledniPoloha){
autoServo();
p++;
delay(500);
  }
  }
  else{
manualServo();
posledniPoloha=p;
  }
}

void manualServo(){ 
for(int i=0; i<CISEL; i++) {
pos[i] = analogRead(pot[i]);
pulse[i] = map(pos[i], 0, 1023, 100, 600);
driverPCA.setPWM(PWM_pin[i], 0, pulse[i]);
}
}

void autoServo(){ 
for (int i=0; i<CISEL; i++) {
pulse[i] = map(m[i][p], 0, 1023, 100, 600);
driverPCA.setPWM(PWM_pin[i], 0, pulse[i]);
}
}
Zkoušel jsem to tímto stylem jak jste říkali((predchozi[x]*(100-rel_pos)/100) + (nove[x]*rel_pos/100)), jenže po zapnutí auto režimu ani obraz ani zvuk, něco jsem tam musel pokazil, buď jsem špatně vytvořil pole nebo jsem to do toho programu špatně dosadil, pak mě napadlo použit cyklus while a zpomalovací podmínku, tam mi to zpomalovalo, ale jen první servo.

Kód: Vybrat vše

...
manualServo();
spos[i]=pos[i];
...
while(spos[i]!=m[i][p]){
autoServo();
if(spos[i]<m[i][p]){
spos[i]++;
delay(10);
}
else if(spos1>m1[i]){
  spos[i]--;
delay(10);
}
}

Dark
Příspěvky: 8
Registrován: 21 pro 2019, 21:37
Reputation: 0

Re: Zpomalení serv s použitím driveru PCA9685

Příspěvek od Dark » 23 pro 2019, 22:12

Nakonec jsem splácal toto:

Kód: Vybrat vše

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>

Adafruit_PWMServoDriver driverPCA = Adafruit_PWMServoDriver(0x40);

#define tl1 11
#define tl2 12

const int CISEL=6;
const int POCET=20;

int m[CISEL][POCET];
int pos[CISEL], spos[CISEL], pulse[CISEL], predchozi[CISEL];
int pot[CISEL]={A0,A1,A2,A3,A6,A7};
int PWM_pin[CISEL]={0,1,2,3,4,5};
int posledniPoloha, p=0, i=0;

void setup() {
  driverPCA.begin();
  driverPCA.setPWMFreq(60);

  pinMode(tl1,INPUT);
  pinMode(tl2,INPUT);
}

void loop() {
  if(digitalRead(tl1)==HIGH){
    for (int i=0; i<CISEL; i++){
      m[i][p]=pos[i];
    }
p++;
delay(500);
}
  if(digitalRead(tl2)==HIGH){
   p=0;
  while(p<posledniPoloha){
autoServo();
p++;
  }
  }
  else{
manualServo();{
spos[i]=pos[i];
posledniPoloha=p;
  }
}
}

void manualServo(){ 
for(int i=0; i<CISEL; i++) {
pos[i] = analogRead(pot[i]);
pulse[i] = map(pos[i], 0, 1023, 100, 600);
driverPCA.setPWM(PWM_pin[i], 0, pulse[i]);
}
}

void autoServo(){ 
for (int i=0; i<CISEL; i++) {
    while(spos[i]!=m[i][p]){
if(spos[i]<m[i][p]){
pulse[i] = map(spos[i], 0, 1023, 100, 600);
driverPCA.setPWM(PWM_pin[i], 0, pulse[i]);
delay(3);
spos[i]++;
}
else if(spos[i]>m[i][p]){
pulse[i] = map(spos[i], 0, 1023, 100, 600);
driverPCA.setPWM(PWM_pin[i], 0, pulse[i]);
delay(3);
spos[i]--;
}
}
}
}
V tomto kódu už serva v režimu auto přejíždějí mezi uloženými polohami zpomaleně, ale jedno po druhém, což tomu odpovídá, jelikož vyvolám vždy jen jedno servo z pole, takže je to časově velice náročné, nevíte jak to udělat aby se přesouvalo všech 6 najednou?
Už mi docházejí nápady -_-

Uživatelský avatar
gilhad
Příspěvky: 786
Registrován: 07 bře 2018, 11:22
Reputation: 0

Re: Zpomalení serv s použitím driveru PCA9685

Příspěvek od gilhad » 24 pro 2019, 03:02

Prohodit ty cykly, pripadne prochazet vetsimi kroky (a trochu ucesat ten kod, hlavne to odsazovani)

Asi nejak takto (ale pisu to z hlavy, bez testovani, muzou tam byt chyby)

Kód: Vybrat vše


#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>

Adafruit_PWMServoDriver driverPCA = Adafruit_PWMServoDriver(0x40);

#define tl1 11
#define tl2 12

const int SERV=6;
const int POCET=20;

int m[POCET][SERV];  // lepsi je mit souvisejici pozice serv ulozene u sebe, nez rozhazene po celem poli
int pos[SERV] ;  // pozice serv
int pot[SERV]={A0,A1,A2,A3,A6,A7};  // piny pro potenciometry
int PWM_pin[SERV]={0,1,2,3,4,5};  // piny pro serva

// pocet kroku, ktere chceme udelat mezi starou a novou pozici
#define STEPS 20

// pocet milisekund, kolik cekame mezi jednotlivymi kroky - STEPS * CEKANI je doba presunu mezi jednotlivymi body (napriklad 20*50 = 1 sec)
#define CEKANI 50

int posledniPoloha=0;  // p a i jsou lokalni promenne ruznych cyklu a deklaruji se az v nich
// posledni Poloha je globalni a ma od zacatku nejakou hodnotu (protoze co kdyz uzivatel zakerne stiskne tlacitko pro autoposun driv, nez neco ulozi)
// (sice nulu nemusime jako pocatecni hodnotu uvadet, ale je to prehlednejsi a pokud nemusime setrit kazdym bytem ...)


void setup() {
  driverPCA.begin();
  driverPCA.setPWMFreq(60);

  pinMode(tl1,INPUT);
  pinMode(tl2,INPUT);
}

void loop() {
  if ( digitalRead(tl1)==HIGH ){ // ulozit pozici (tlacitko 1)
    ulozPozici();
    delay(50); // debounce tlacitka 
    while ( digitalRead(tl1)==HIGH ) {}; // pockat, dokud nepusti tlacitko
    delay(50); // debounce pusteni tlacitka 
  }  // end ulozeni pozice (tlacitko 1)
  
  if( digitalRead(tl2)==HIGH ){ // automaticky pohyb (tlacitko 2)
    ulozPozici();  // po skonceni se vratime tam, kde jsme zacali, at nasledujici manualServo nam necukne vsema servama, 
       // pokud jsme odjeli z posledniho ulozeneho bodu
    for (int p=0; p < posledniPoloha; p++){
      autoServo(p);
    }
    posledniPoloha--; // uz jsme zpatky, takze tu polohu muzeme zase zapomenout
  } // konec automatickeho pohybu 
  else {  // manualni pohyb
    manualServo();
  }  // konec tlacitka 2

// pokud treti tlacitko neni RESET a/nebo nechceme cukat servama
//  if ( digitalRead(tl3)==HIGH ){ // vymazat pozice
//    posledniPoloha = 0; // resetovat index posledni Pozice
//    delay(50); // debounce tlacitka 
//    while ( digitalRead(tl3)==HIGH ) {}; // pockat, dokud nepusti tlacitko
//    delay(50); // debounce pusteni tlacitka 
//  }  // end vymazani pozic

}

void ulozPozici() { // prida aktualni pozici na konec pole
   // globalni pole m, pos a promenna posledniPoloha
   
   if (posledniPoloha >= POCET) { // jsme na konci pole, nechceme pretect
      posledniPoloha=POCET-1; // zapomeneme posledni bod (ci body, ale to by se nam nemelo stat) a ted uz mame kam ukladat
    } // end testovani preteceni
   
    for (int i=0; i<SERV; i++){
      m[posledniPoloha][i]=pos[i];
    } // end for i
    posledniPoloha++; // zvednout index posledni Pozice
} // end ulozPozici

void manualServo(){ 
  // globalni pole pos[?]
  
  for(int i=0; i<SERV; i++) {
    pos[i] = analogRead(pot[i]);
    driverPCA.setPWM(PWM_pin[i], 0, map(pos[i], 0, 1023, 100, 600););
  } // end for i
}  // end manualServo



void autoServo(int p){  // p je index pozadovane pozice
  // globalni pole m[p][?] obsahuje cilove pozice pro jednotliva serva
  // globalni pole pos[?] obsahuje vychozi pozice jednotlivych serv
  
  for (int st=1; st<STEPS+1; st++) {  // v bode nula uz jsem, potrebuju skoncit v bode STEPS, ne o krok driv, cyklus 1..STEPS
    for (int i=0; i<SERV; i++) { // pro kazde servo ...
//      int x =  ((pos[i]*(STEPS-st)/STEPS) + (m[i][p]*st/STEPS)) ; // moc hezky, ale pro velke STEPS muze pretect, radeji to opatrne rozepiseme
      long int x = (long)pos[i] * (STEPS-st) + (long)m[i][p] * st; // porad bychom meli pocitat s long cisly
      x = x / STEPS;  // a ted to podelime. Staci nam jedna promenna, protoze ji hned pouzijeme a pak uz dal nepotrebujeme
      driverPCA.setPWM(PWM_pin[i], 0, map(x, 0, 1023, 100, 600));
    } // end for i
    delay(CEKANI); // nejdriv nastavime naraz pohyb vsemi servy o jeden krok, pak teprve pockame, az ten krok udelaji (spolecne)
  }  // end for st
  
  for (int i=0; i<SERV; i++) { // pro kazde servo ...
    pos[i] = m[i][p]; // ... nastavime stavajici pozici na cilovy bod
  }
}  // end autoServo

Plus by samozrejme slo obejit delay a behem ni delat neco uzitecneho (cist tlacitka, blikat, ... ), ale tim by se ten program ponekud zkomplikoval (v podstate bychom pak potrebovali stavovy automat)

Dark
Příspěvky: 8
Registrován: 21 pro 2019, 21:37
Reputation: 0

Re: Zpomalení serv s použitím driveru PCA9685

Příspěvek od Dark » 25 pro 2019, 21:17

Tak, program jsem dnes zkoušel, ale jen z rychlíku, nesmírně si vážím toho že jsi obětoval tolik času, máš to všechno pěkně vysvětlené, taky je dobrý nápad tam dát ten debounce tlačítka a použit místo resetu tlačítko, které nuluje pozice atd. Zatím jsem neměl moc času program vyzkoušet, zkoušel jsem ho se 2 servy a potenciometry, a zatím jsem vysledoval pár menších problému (např. že jedno ze dvou serv najede po spuštění do krajní pozice, ze které se nehne, to se děje když uložím méně než 4 pozice, když jich je více, tak už tento problém není, zkusím ten problém nějak pořešit, zatím nevím čím to je, pak při přepnutí z auto do manuálu se pořesune plnou rychlosti, to už jsem pořešil :) ) Ještě stále zvažuji jestli přece jen nepoužit pro auto režim spíše podmínku, protože ta má výhodu v tom, že oproti tomu výpočtu, který když chci posunout servem jen o stupeň, tak to trvá prakticky téměř stejně dlouho, jako když ho otáčím o 180 stupňů (tudíž někdy jede trochu zbytečně pomalu mezi pozicemi a někdy naopak rychle), s podmínkou to jelo vždy stejnou rychlostí a s trochu větší přesností, ale to je jen můj dojem. Takže během tohoto týdne si k tomu ještě sednu a zkusím opravit ty drobné problémy a pošlu ti výsledný program. A ještě jednou moc cením a díky za to, že jsem se zase něco nového naučil.

Uživatelský avatar
gilhad
Příspěvky: 786
Registrován: 07 bře 2018, 11:22
Reputation: 0

Re: Zpomalení serv s použitím driveru PCA9685

Příspěvek od gilhad » 26 pro 2019, 16:20

S tou inkrementaci/dekrementaci ti serva jedou stejnou rychlosti (a ta s kratsi drahou dorazi na misto driv, nez ta s dlouhou, takze to nejdriv jede jinam a pak dorazi "pravouhle"), s delenim drahy zase stejnou dobu a dorazi vsechny stejne, idealni by asi bylo nemit STEPS jako konstantu, ale promennou a pro kazdy presun to vypocist z maximalniho rozdilu souradnic (tedy otaceni serva), pak by to vicemene plynule jelo vsemi servy servy naraz, pricemz tempo by udavalo to s nejdelsi drahou a ostatni by se prizpusobily.

S tou krajni pozici je to podezrele, nech si na Serial vypsat, odkud a kam to ma jet, pokud to bude "divne", tak i vypat vsechna pole pred zacatkem pohybu a prubezne ty mezihodnoty. (muze tam byt neco o 1 vedle, nebo to pretypovavani chtit jeste dukladneji)

Odpovědět

Kdo je online

Uživatelé prohlížející si toto fórum: Žádní registrovaní uživatelé a 16 hostů