• Witaj na Forum Arduino Polska! Zapraszamy do rejestracji!
  • Znajdziesz tutaj wiele informacji na temat hardware / software.
Witaj! Logowanie Rejestracja


Ocena wątku:
  • 0 głosów - średnia: 0
  • 1
  • 2
  • 3
  • 4
  • 5
Accelestepper i kłopoty
#11
Zaprezentowany w poprzednim poście szkic działa OK. Sprawdzałem go co prawda tylko analizatorem, ale teraz zmontowałem dwa silniki i kręcą się OK.
https://youtu.be/VZdZk0orGFo
Może masz inny silnik, inaczej ustawione/włączone mikrokroki i wtedy oczywiście będą inne prędkości (moje mają pełne kroki). Może coś pomieszałeś z podłączeniem kabli lub definicją pinów. Może masz ograniczony prąd za bardzo napięciem na driverze, albo za słabe zasilanie.
Ja to podłączyłem na szybko do shielda RAMP 1.5  z driverami A4988, akurat ten shield wymaga sterowania jeszcze pinem ENABLE, więc to i zmiana pinów, które są przeznaczone na shieldzie dla osi X i Y, które wykorzystałem do zasilenia silników, to jedyne modyfikacje.
Dopóki nie zaczną działać jak na filmiku z tym szkicem nie ma sensu brnąć dalej. To co chcesz osiągnąć to już tylko odpowiedni dobór funkcji biblioteki i ułożenie logiki, odpowiedni dobór dostępnych dla programisty algorytmów.
Kod:
#include <AccelStepper.h>

const int stepPin1 = A0; // Silnik nr 1  ruch poziomy
const int dirPin1 = A1;
const int enablePin1 = 38;
const int stepPin2 = A6;  //Silnik nr 2 ruch obrotowy głowicy
const int dirPin2 = A7;
const int enablePin2 = A2;

AccelStepper stepper1 = AccelStepper(1, stepPin1, dirPin1 );
AccelStepper stepper2 = AccelStepper(1, stepPin2, dirPin2 );

uint32_t czasTeraz,czasPoprzedni,tik=10;
uint8_t nTik,sekundy,minuty,godziny,dni;
bool fnTik,fsekundy,fminuty,fgodziny,fdni;
char napis[64];

void setup() {
Serial.begin(115200);
pinMode(enablePin1,OUTPUT);
pinMode(enablePin2,OUTPUT);
digitalWrite(enablePin1, LOW) ;
digitalWrite(enablePin2, LOW) ;
  stepper1.setMaxSpeed(100);
  stepper1.setAcceleration(50);
  stepper1.moveTo(100);
  stepper2.setMaxSpeed(300);
  stepper2.setAcceleration(100);
  stepper2.moveTo(100);
}


void loop()
{
  czas();
if (stepper1.distanceToGo() <=100)   stepper1.moveTo (stepper1.currentPosition()-50) ;
if (stepper2.distanceToGo() <=100)   stepper2.moveTo (stepper2.currentPosition()+50) ;

stepper1.run();
stepper2.run();

if(fsekundy) {

  Serial.print(sekundy);
  sprintf(napis," Silnik1: %6d",stepper1.currentPosition() );
  Serial.print(napis);
  sprintf(napis," Silnik2: %6d",stepper2.currentPosition() );
  Serial.println(napis);
}

}






void czas()
{
  czasTeraz=millis();
fnTik=fsekundy=fminuty=fgodziny=fdni=0;
if((uint32_t)(czasTeraz-czasPoprzedni)>=tik)
{
  czasPoprzedni=czasTeraz;
  fnTik=1;
  nTik++;
  if(nTik>=(1000/tik))
  {
    nTik=0;
    sekundy++;
    fsekundy=1;
     if (sekundy>=60)
    {
      sekundy=0;
      minuty++;
      fminuty=1;
      if (minuty>=60)
      {
        minuty=0;
        godziny++;
        fgodziny=1;
        if (godziny>=24)
        {
          godziny=0;
          fdni=1;
          dni++;
   
        }
      }
    }
  }
}
}
Miło być decenianym https://buycoffee.to/kaczakat
 
Odpowiedź
#12
Dzięki, masz rację. Pomieszałem kabelki. Teraz się kręcą.
Mam pytanie dot funkcji czas(). Jak dobrze zrozumiałem kod, związana jest ona tylko z wyświetlaniem informacji w porcie szeregowym. Mam rację? Po wyeliminowanie z kodu elementów związanych z tą funkcją silniki nadal pracują. Próbowałem zmodyfikować ten kod, tak by wykonywał się "n" razy co 2 sekundy. I znowu porażka. Nie ma ruchu. Dochodzę do wniosku, że jedyne co mi wychodzi to mruganie diodą na pinie 13.

#include <AccelStepper.h>

const int stepPin1 = 7; // Silnik nr 1 ruch poziomy
const int dirPin1 = 6;
const int enablePin1 = 10;
const int stepPin2 = 9; //Silnik nr 2 ruch obrotowy głowicy
const int dirPin2 = 8;
const int enablePin2 = 11;

bool flag = true;

AccelStepper stepper1 = AccelStepper(1, stepPin1, dirPin1 );
AccelStepper stepper2 = AccelStepper(1, stepPin2, dirPin2 );

uint32_t czasTeraz,czasPoprzedni,tik=10;
uint8_t nTik,sekundy,minuty,godziny,dni;
bool fnTik,fsekundy,fminuty,fgodziny,fdni;
char napis[64];

void setup() {
Serial.begin(115200);
pinMode(enablePin1,OUTPUT);
pinMode(enablePin2,OUTPUT);
digitalWrite(enablePin1, LOW) ;
digitalWrite(enablePin2, LOW) ;
stepper1.setMaxSpeed(1000);
stepper1.setAcceleration(50);
stepper1.moveTo(2000);
stepper2.setMaxSpeed(3000);
stepper2.setAcceleration(100);
stepper2.moveTo(2000);
}
void loop()
{

if(flag){
for(int i = 0; i <= 3; i++){
ruch();

delay(2000);
}
flag = false;}
}
void ruch(){
if (stepper1.distanceToGo() <=2000) stepper1.moveTo (stepper1.currentPosition()-2000) ;
if (stepper2.distanceToGo() <=2000) stepper2.moveTo (stepper2.currentPosition()+2000) ;

stepper1.run();
stepper2.run();

}
 
Odpowiedź
#13
Funkcja czas() jest do wszystkiego w programie. Niektóre rzeczy muszą być robione w każdym loop i tylko wtedy nie używam funkcji czas() i jej zmiennych.
Arduino jest oparte o gotowe funkcje, normalnie w C z AVR można realizować polecenia bezpośrednio na rejestrach uC, wtedy taka najmniejsza jednostka programowa trwa 62ns przy zegarze 16MHz, 16mln operacji w sekundę. Ale do każdego uC trzeba napisać inny program. Arduino upraszcza to ujednolicając polecenia do różnych uC analizując funkcjami jaki zestaw poleceń wykonać w każdym przypadku i to powoduje spadek wydajności do <1mln /s. Ale to tylko przy miganiu LED, są funkcje, które zajmują po 20ms i wtedy można ich zrobić w 1s tylko 50. Jak będą wywoływane zbyt często to będzie to działać jak Windows z komputerem sprzed 3 dekad. Jak wstawiasz w loop delay 2000 to pewnie tworzysz funkcję, która potrwa powyżej 2000ms, a to nie zadziała dobrze. Porównaj sobie teraz, jak zacznie pracować Twój PC, gdy mu zmienisz ilość cykli zegara z 3GHz do 1kHz, tak z 3mln x wolniej, życia braknie.
Jeśli silnik ma mieć prędkość 3000 to nie możesz zrobić loop trwającego dłużej niż 1s/3000. Może trzeba zmniejszyć podział mikrokroków kosztem płynności jazdy. Albo znaleźć bibliotekę do stepera opartą o przerwania, tak by sterowanie nim było niezależne od długości loop. Może uC z zegarem 240MHz (ESP32) zamist 16MHz.
Funkcja czas jest do zarządzania czasem, możesz wymyślić inną, opartą o timer sprzętowy, albo inną opartą jak moja o millis(), ale z delay zrobienie programu jest nierealne. To jest tylko do szybkiego pokazania jednej, max dwu funkcji, tak by spowolnić ich działanie do możliwej dla zaobserwowania dla człowieka, do zrobienia DEMO. W każdym programie użytkowym jakoś trzeba czasem zarządzać.
Funkcja czas ustawia flagi różnych okresów czasu na 0 (bez względu na ich stan) i sprawdza czy minął czas>=tik, jeśli tak ustawia flagę fnTik tego najmniejszego okresu. Wartość okresu tik można sobie ustalić wg potrzeb. W tym loop gdy to nastąpi można to wykorzystać np. do okresowego sprawdzania stanu pinu z przyciskiem. Dalej w funkcji czas jeśli minął okres tik, zwiększana jest suma tików nTik i jak przekroczy liczbę równą sekundzie ustawiona jest flaga dla sekund. W tym konkretnym obiegu loop gdy to się stanie zadziałają wszystkie funkcje w bloku if(fsekundy). Jednocześnie jest zwiększany licznik sekund, analogicznie minut, godzin, dni i ich flagi. Gdy minie dzień od poprzedniego dnia tylko raz w jednym obiegu funkcji loop będzie taki stan flagi fdni, np. by nasypać psu do miski karmy, bez wstawiania delay na 24h.
Potem można wykorzystać to w różnych funkcjach i nie trzeba przywoływać w każdej funkcji millis(), która trwa z 10us. Można łatwo coś wykonać co 200ms, jest to wtedy gdy jest flaga fnTik==1 i liczba tików taka, że reszta z dzielenia przez 20 jest równa 0: if (fnTik and (nTik%20==0)).
Do każdego zadania jest odpowiednie narzędzie, do wielu długich zadań pasuje maszyna stanów z konstrukcją switch case. Podziel sobie całe zadanie na etapy do zrealizowania, np. pozycja 0 i oczekiwanie na ruch, przejazd silników do pozycji 1, oczekiwanie, przejazd do pozycji 2, oczekiwanie, powrót do pozycji 0 i powtórzenie cyklu. Oczywiście oczekiwanie to nie delay, to liczenie i sprawdzanie czy upłynęło już tyle ms/us by przejść do kolejnego punktu zadania. Potem kolejnym krokiem jest budowanie zestawu takich funkcji do różnych przejazdów kamery, z różnymi parametrami prędkości.
Tu jest przykład jak tworzyć taką funkcję: https://www.youtube.com/watch?v=v8KXa5uRavg .
Miło być decenianym https://buycoffee.to/kaczakat
 
Odpowiedź
#14
Dziękuję Ci bardzo za obszerne wyjaśnienia. Dużo czasu spędziłem, by to dobrze zrozumieć, ale się nie udało. Główną przyczyną jest moje całkowite dyletanctwo w kwestii programowania Arduino. Tematem tym zajmuję się dosłownie od dwóch tygodni, nie mając wcześniej żadnego doświadczenia w jakimkolwiek programowaniu. A robię to głównie po to, by utrzymać w jako takiej sprawności mój umysł, bowiem jestem już wiekowym człowiekiem. Doszedłem do wniosku, że trzeba iść do przodu małymi kroczkami. I takim małym kroczkiem byłoby wyjaśnienie mi dlaczego poniższy kod nie zatrzymuje silników po 5 sek?
Jeszcze raz Ci dziękuję i pozdrawiam.
Ta korespondencja nie jest widoczna na forum. Czy ma ona charakter prywatny?
#include <AccelStepper.h>
float Dp = 10 ; // Długość przejazdu (cm)
const int Kog = 180 ; // Kąt obrotu głowicy w st.
const int s = 10 ; // Czas przejazdu (sek)
const int Prp = 800 ; // Prędkość w poziomie( kroki/sek)
const int Pro = 480 ; //Prędkość głowicy( kroki/sek)

unsigned long Ac = 0; // Aktualny cas
unsigned long Zc = 0; // Zapamiętany czas
unsigned long Rc = 0; // Różnica czasu( Ac-Zc)
bool flag = true;


AccelStepper stepper1(1, 7, 6);
AccelStepper stepper2(1, 9, 8);
const int enablePin1 = 10; // Steruje wyłączaniem sterowników
const int enablePin2 = 11;

void setup() {
pinMode(enablePin1,OUTPUT);
pinMode(enablePin2,OUTPUT);
digitalWrite(enablePin1,LOW);
digitalWrite(enablePin2,LOW);

stepper1.setMaxSpeed(10000);
stepper2.setMaxSpeed(10000);

stepper1.setSpeed(Prp);
stepper2.setSpeed(Pro);
}

void loop() {
if (flag=true){
Ac = millis();
Rc = Ac-Zc;

if (Rc <= 5000UL) {

Zc = Ac;

stepper1.runSpeed();
stepper2.runSpeed();
}
else
{
digitalWrite(enablePin1,HIGH);
digitalWrite(enablePin2,HIGH);

}

}
flag=false;
}
 
Odpowiedź
#15
Ac rośnie razem z milisekundami działania, spełnia się warunek if (Rc<=5000) i Zc przypisujesz aktualną wartość Ac, Zc ma ciągle wartość równą Ac pod koniec pętli loop i niewiele mniejszą w następnym obiegu, Rc jest ciągle blisko 0 bo to coś minus (coś-niewiele) i warunek spełnia się dalej.
Miło być decenianym https://buycoffee.to/kaczakat
 
Odpowiedź
#16
Rozumiem, wobec powyższego zmieniłem kod. Niby działa, ale nie wiem, czy jest to zgodne ze sztuką.
void loop() {
if (flag=true){
Ac = millis();
Rc = Ac-Zc;
if (Rc >= 5000UL) {
Zc = Ac;
digitalWrite(enablePin1,HIGH);
digitalWrite(enablePin2,HIGH);
flag=false;
}
else
{
stepper1.runSpeed();
stepper2.runSpeed();
}
}}
 
Odpowiedź
#17
Zgodnie ze sztuką Arduino jak miga led i nic więcej nie oczekujesz od programu to jest OK. Po prostu ciężko nad takim kodem pracować dalej, dodawać kolejne funkcje, np. dodać wybór różnych przejazdów różnymi przyciskami bez resetowania urządzenia i wgrywania osobnego programu dla każdego efektu.
Miło być decenianym https://buycoffee.to/kaczakat
 
Odpowiedź
#18
No, tak myślałem, że na odległość cuchnie potworną amatorszczyzną.
Teraz do tego będę chciał dołożyć wyświetlacz oled i enkoder obrotowy, by za ich pomocą wprowadzać parametry ruchu bez konieczności każdorazowego wgrywania programu. Może mi się uda, choć pierwsze lekcje dot. enkodera wydają mi się dość trudne.
Wielkie dzięki za dotychczasową pomoc.
 
Odpowiedź
  


Skocz do:


Przeglądający: 1 gości