Skocz do zawartości

Arduino - wysuw siłownika po jednym pełnym obrocie silnika


Michal94

Pomocna odpowiedź

#include <AccelStepper.h>
#include <Wire.h>   

AccelStepper stepper(1, 2, 4);      // Silnik 1 i 2
#define PRZEKAZNIK_P3 20      // Przekaźnik siłownika łapiącego stretch
#define PRZEKAZNIK_P4 21      // Przekaźnik siłowników szczęk

unsigned long aktualnyCzas = 0;
unsigned long zapamietanyCzasP3Start = 0;
unsigned long zapamietanyCzasP4Start = 0;
unsigned long zapamietanyCzasP3Stop = 0;
unsigned long zapamietanyCzasP4Stop = 0;
unsigned long zapamietanyCzasStepperStart = 0;


int liczP3start = 0;
int liczP3stop = 0;
int liczP4start = 0;
int liczP4stop = 0;
int liczstepper = 0;
int liczmaks = 1;



void setup() {
  
   Serial.begin(9600);      
   stepper.setMaxSpeed(1750);     
   stepper.setAcceleration(1000);      
   pinMode(PRZEKAZNIK_P3, OUTPUT);     
   pinMode(PRZEKAZNIK_P4, OUTPUT);     

}

void loop() {
  

   aktualnyCzas = millis();
   
   if ((aktualnyCzas - zapamietanyCzasP3Start >= 1000UL) && (liczP3start < liczmaks)) {
   zapamietanyCzasP3Start = aktualnyCzas;
   digitalWrite(PRZEKAZNIK_P3, HIGH);      
   liczP3start++;
   }
   
   if ((aktualnyCzas - zapamietanyCzasStepperStart >= 2000UL) && (liczstepper < liczmaks)) {
   zapamietanyCzasStepperStart = aktualnyCzas;
   stepper.move(11200);      
   stepper.runToPosition();     
   liczstepper++;  
   }  
      
   if ((aktualnyCzas - zapamietanyCzasP4Start >= 3000UL) && (liczP4start < liczmaks)) {
   zapamietanyCzasP4Start = aktualnyCzas;
   digitalWrite(PRZEKAZNIK_P4, HIGH);      
   liczP4start++; 
   }
   
   if ((aktualnyCzas - zapamietanyCzasP4Stop >= 4000UL) && (liczP4stop < liczmaks)) {
   zapamietanyCzasP4Stop = aktualnyCzas;
   digitalWrite(PRZEKAZNIK_P4, LOW);      
   liczP4stop++; 
   }
   
   if ((aktualnyCzas - zapamietanyCzasP3Stop >= 5000UL) && (liczP3stop < liczmaks)) {
   zapamietanyCzasP3Stop = aktualnyCzas;
   digitalWrite(PRZEKAZNIK_P3, LOW);     
   liczP3stop++;
   }  

Dzień dobry,

Chciałbym aby po wykonaniu jednego obrotu silnika poszedł sygnał na przekaźnik P4, próbowałem zrobić to przy użyciu funkcji millis niestety nic to nie dało. Czy ktoś zna sposób na wykonanie takiej akcji ?

Z góry dziękuje za odpowiedź

Pozdrawiam

Link do komentarza
Share on other sites

35 minut temu, ethanak napisał:

nie używać runToPosition (bo to funkcja blokująca) tylko sprawdzać w jakiej pozycji po run() jest silnik?

Coś więcej można prosić ? Silnik miałby wykonać 28 obrotów.

Link do komentarza
Share on other sites

jeśli używasz runToPosition funkcja po prostu czeka we własnej pętli na zakończenie ruchu silnika i przez ten czas nie możesz zrobić nic innego. jeeśli wywołujesz po prostu run() w pętli bez żadnych opóźnień, jesteś w stanie stwierdzić w jakiej pozycji jest silnik i zależnie od tego odpowiednio zareagować. oczywiście wymaga to napisania programu w trochę inny sposób...

wyobraź sobie że runToPosition to taki delay tylko trochę bardziej skomplikowany. 

  • Pomogłeś! 1
Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

(edytowany)
#include <AccelStepper.h>
#include <Wire.h>   

AccelStepper stepper(1, 2, 4);      // Silnik 1 i 2
#define PRZEKAZNIK_P3 20      // Przekaźnik siłownika łapiącego stretch
#define PRZEKAZNIK_P4 21      // Przekaźnik siłowników szczęk

unsigned long aktualnyCzas = 0;
unsigned long zapamietanyCzasP3Start = 0;
unsigned long zapamietanyCzasP4Start = 0;
unsigned long zapamietanyCzasP3Stop = 0;
unsigned long zapamietanyCzasP4Stop = 0;
unsigned long zapamietanyCzasStepperStart = 0;


int liczP3start = 0;
int liczP3stop = 0;
int liczP4start = 0;
int liczP4stop = 0;
int liczstepper = 0;
int liczmaks = 1;
int pos = 11200;


void setup() {
  
   Serial.begin(9600);      
   stepper.setMaxSpeed(1750);     
   stepper.setAcceleration(1000);
   stepper.moveTo(pos);       
   pinMode(PRZEKAZNIK_P3, OUTPUT);     
   pinMode(PRZEKAZNIK_P4, OUTPUT);     

}

void loop() {
  

   aktualnyCzas = millis();
   
   if ((aktualnyCzas - zapamietanyCzasP3Start >= 1000UL) && (liczP3start < liczmaks)) {
   zapamietanyCzasP3Start = aktualnyCzas;
   digitalWrite(PRZEKAZNIK_P3, HIGH);      
   liczP3start++;
   }
   
   if ((aktualnyCzas - zapamietanyCzasStepperStart >= 2000UL) && (liczstepper < liczmaks)) { 
   zapamietanyCzasStepperStart = aktualnyCzas;
   while (stepper.distanceToGo() > 0) {   
   stepper.run();
   }   
   liczstepper++; 
   }   
      
   if ((aktualnyCzas - zapamietanyCzasP4Start >= 3000UL) && (liczP4start < liczmaks)) {
   zapamietanyCzasP4Start = aktualnyCzas;
   digitalWrite(PRZEKAZNIK_P4, HIGH);      
   liczP4start++; 
   }
   
   if ((aktualnyCzas - zapamietanyCzasP4Stop >= 4000UL) && (liczP4stop < liczmaks)) {
   zapamietanyCzasP4Stop = aktualnyCzas;
   digitalWrite(PRZEKAZNIK_P4, LOW);      
   liczP4stop++; 
   }
   
   if ((aktualnyCzas - zapamietanyCzasP3Stop >= 5000UL) && (liczP3stop < liczmaks)) {
   zapamietanyCzasP3Stop = aktualnyCzas;
   digitalWrite(PRZEKAZNIK_P3, LOW);     
   liczP3stop++;
   }  
}

Zmieniłem funkcje runToPosition na run ale dalej pojawia się podobny problem. Program blokuje się na pętli while. Wiem że funkcja run musi być cały czas wywoływana jeśli silnik ma wykonywać pracę.

Czy zamiana pętli while na for może pomóc ?

Edytowano przez Michal94
Link do komentarza
Share on other sites

Nie - ta pętla jest w ogóle niepotrzebna, przecież już jedną pętlę masz (w której działa loop()) - po co jeszcze druga wewnątrz? Podobnie jak wszystkie zmienne o fajnych nazwach liczpcośtam - po co, jeśli możesz wywołać stepper.currentPosition() czy stepper.distanceToGo() i po prostu sczytać pozycję bezpośrednio z instancji steppera? Coś mi się wydaje, że nie raczyłeś zajrzeć do dokumentacji biblioteki... łap sznurek

Przy okazji - zdradź tajemnicę po co Ci te czasy zapamiętane, bo chciałem Ci dokładniej napisać ale ni czorta z nich nie rozumiem 😞

 

 

Edytowano przez ethanak
  • Lubię! 1
Link do komentarza
Share on other sites

(edytowany)

Głównie chodzi o to żeby siłownik sterowany z przekaźnika P4 wysunął się podczas pracy silnika (po jakimś konkretnym czasie albo po wykonaniu konkretnej liczby obrotów [nie zatrzymując przy tym silnika]). Wiem że przy użyciu delay tego się nie osiągnie ponieważ komenda przerywa program.

Program nie będzie działać w pętli. Miałby wykonywać się tylko raz

Czasy w obecnym programie są zupełnie przypadkowe, dopiero po napisaniu gotowego programu oraz zmontowaniu urządzenia które będzie sterowane czasy będą regulowane.

Zaglądałem do tej dokumentacji.

 

Edytowano przez Michal94
Link do komentarza
Share on other sites

To że ma się wykonać tylko raz nie oznacza, że w środku nie ma być pętli!

Funkcja loop działa w pętli, a czy w niej cokolwiek się wykonuje czy nie to zupełnie inna para gaci.

Wyobraź sobie taki algorytm (zaczynamy od tego, że przy starcie programu warunek "silnik włączony" jest zawsze spełniony):
 

1. Czy silnik włączony? jeśli tak, nic nie rób i kończ wykonanie funkcji.
2. Czy wskutek wykonania run() silnik zrobił krok? Jeśli nie, nic nie rób i kończ wykonanie funkcji.
3. Czy osiągnięto pozycję końcową do wyłączenia silnika? Jeśli tak, wyłącz silnik i kończ wykonanie funkcji.
4. Czy przekaźnik P4 jest załączony, jeśli nie to:
   4a: Czy osiągnięto pozycję w której P4 powinien się włączyć? Jeśli tak, włącz P4.

Jeśli dodatkowo zadajesz czas po którym P4 ma się włączyć (nie wiem po co, przecież to wynika z działania samej funkcji run()), zawsze możesz dodać:

   4a: Czy osiągnięto pozycję w której P4 powinien się włączyć? Jeśli tak, włącz P4. Jeśli nie, to:
	4b: Czy osiągnięto czas po którym powinien się włączyć P4? Jeśli tak, włącz P4.

I pamiętaj: wszelkie działania inicjalizacyjne (takie, które mają byc wykonane tylko raz w programie) umieszczasz w setup() a nie na początku loop()!

Link do komentarza
Share on other sites

#include <AccelStepper.h>
#include <Wire.h>   

AccelStepper stepper(1, 2, 4);      
#define P3 20      
#define P4 21      

int pos = 11200;

void setup() {
  
   Serial.begin(9600);      
   stepper.setMaxSpeed(1750);     
   stepper.setAcceleration(1000);
   stepper.moveTo(pos);
          
   pinMode(P3, OUTPUT);     
   pinMode(P4, OUTPUT);  

   delay(1000);   
   digitalWrite(P3, HIGH);
   delay(1000);
   silnik();
   if (stepper.distanceToGo() == 11000) {
   digitalWrite(P4, HIGH);
   delay(200);
   digitalWrite(P4, LOW);
   }
   delay(5000);
   digitalWrite(P3, LOW);
}

void loop() {
}

void silnik(){
  while(stepper.distanceToGo() > 0) {
  stepper.run();
  } 
}

Czy przy takim programie da się wywołać przekaźnik podczas obrotów silnika ?

Link do komentarza
Share on other sites

Po co kombinujesz? Przecież sam wiesz że nie, prawda? Funkcja silnik() będzie działać nieprzerwanie aż stepper.distanceToGo() zwróci zero, i żebyś nie wiem jak się modlił po powrocie z tej funkcji nie ma szans, aby nagle zwróciła 11000 (albo jakąkolwiek inną wartość różną od zera). Napisałem Ci jak ma wyglądać funkcja loop() - chcesz to skorzystaj, nie chcesz - nie musisz.

Jeśli już koniecznie chcesz po swojemu z jakimiś swoimi pętlami, to:

void silnik(){
	while(stepper.distanceToGo() > 0) {
		stepper.run();
		/* tu jest miejsce na włączanie przekaźników a nie w setup */
	}
}

Tylko po co pisać drugą funkcję loop co się nazywa silnik?

 

  • Pomogłeś! 1
Link do komentarza
Share on other sites

Dzięki powyższej pomocy program działa jak należy.

Teraz próbuje napisać program, który podczas obrotów silnika będzie liczył elementy. Po odliczeniu pewnej ilości silnik miałby się zatrzymać. Do liczenia został użyty czujnik przerwania wiązki IR. Mam świadomość że kiedy wiązka jest przerwana to wartość "i" będzie rosła cały czas do nieskończoności. W tym wypadku chciałbym żeby wartość "i"  rosła tylko o 1 podczas zmiany wartości stanu napięcia czujnika. Czy jest to do wykonania ?

Z góry dziękuje za pomoc.

 

void przenosnik(){
  while(stepper.distanceToGo() > 0) {
  stepper.run();
  if (digitalRead(CZ) == LOW) {
  i++;
  if (i == 25) {
  stepper.setSpeed(0);    
  }
  }
  }
}  

 

Link do komentarza
Share on other sites

A po co w programach są zmienne? Po to, żeby sobie coś zapamiętać, prawda? No więc zapamiętaj sobie w jakiejś zmiennej globalnej (albo statycznej) stan CZ, a potem porównaj z bieżącym. Jeśli poprzedni jest 0 a bieżący 1 to znaczy że była zmiana.

Coś takiego mniej więcej:

bool element(void)
{
  static int old_cz = LOW;
  int new_cz = digitalRead(CZ);
  bool rc = old_cz == LOW && new_cz == HIGH;
  old_cz = new_cz;
  return rc;
}

  
  

Taka funkcja zwróci true tylko wtedy, kiedy element się pokazał.

Link do komentarza
Share on other sites

Hm... kto tu pisze program, ja czy Ty?

Ostatni przykład na dziś:

ile = 0;
while (stepper.distanceToGo() > 0) {
	stepper.run();
	/* tu jakieś przekaźniki albo inne wymysły */
	if (element()) {
		ile++;
		if (ile >= ILOSC) break;
	}
}

Aha: zawsze używaj w takich przypadkach operatorów typu "większe lub równe" a nie "równe" - w tym przypadku to nie ma znaczenia, ale czasem może prowadzić do trudnych do znalezienia błędów.

Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.