Skocz do zawartości
MarcinTe

Arduino + wozek inwalidzki (sterowanie 2 silnikow)

Pomocna odpowiedź

Czesc,

Robie wozek inwalidzki oparty na 2 silnikach, joystick porusza wozek, przycisk obraca go w miejscu, wszystko dziala.

Problem w tym ze joystick jest maly i silniki bardzo agresywnie reaguja, chcialbym zeby po natychmiastowym wychyleniu do przodu predkosc nie skoczyla od razu do wartosci maksymalnej tylko chwile plynnie do niej dochodzila. Bede wdzieczny za pomoc. Dzieki.

// FINAL Z 1 PRZYCISKIEM ENDER 3

// Button

const int switchPin = 2;
int switchValue;
  
// Motor A
 
int enA = 9;
int in1 = 8;
int in2 = 7;
 
// Motor B
 
int enB = 3;
int in3 = 5;
int in4 = 4;
 
// Joystick Input
 
int joyVert = A0; // Vertical  
int joyHorz = A1; // Horizontal
 
// Motor Speed Values - Start at zero
 
int MotorSpeed1 = 0;
int MotorSpeed2 = 0;

// Joystick Values - Start at 512 (middle position)
 
int joyposVert = 512;
int joyposHorz = 512;  
 
 
void setup()
 
{

   Serial.begin(9600);
   
//button
   
 pinMode(switchPin, INPUT_PULLUP);
  
  // Set all the motor control pins to outputs
 
  pinMode(enA, OUTPUT);
  pinMode(enB, OUTPUT);
  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
  pinMode(in3, OUTPUT);
  pinMode(in4, OUTPUT);
   
  // Start with motors disabled and direction forward
  
  // Motor A
  
  digitalWrite(enA, LOW);
  digitalWrite(in1, HIGH);
  digitalWrite(in2, LOW);
  
  // Motor B
  
  digitalWrite(enB, LOW);
  digitalWrite(in3, HIGH);
  digitalWrite(in4, LOW);
  
}
 
void loop() {

// button state

   switchValue = digitalRead(switchPin);

 if (switchValue==1) {

  // Read the Joystick X and Y positions
 
  joyposVert = analogRead(joyVert); 
  joyposHorz = analogRead(joyHorz);
 
  // Determine if this is a forward or backward motion
  // Do this by reading the Verticle Value
  // Apply results to MotorSpeed and to Direction
 
  if (joyposVert < 460)
  {
    // This is Backward
 
    // Set Motor A backward
 
    digitalWrite(in1, LOW);
    digitalWrite(in2, HIGH);
 
    // Set Motor B backward
 
    digitalWrite(in3, LOW);
    digitalWrite(in4, HIGH);
 
    //Determine Motor Speeds
 
    // As we are going backwards we need to reverse readings
 
    joyposVert = joyposVert - 460; // This produces a negative number
    joyposVert = joyposVert * -1;  // Make the number positive
 
   MotorSpeed1 = map(joyposVert, 0, 460, 0, 255);
   MotorSpeed2 = map(joyposVert, 0, 460, 0, 255);

 
  }
  else if (joyposVert > 564)
  {
    // This is Forward
 
    // Set Motor A forward
 
    digitalWrite(in1, HIGH);
    digitalWrite(in2, LOW);
 
    // Set Motor B forward
 
    digitalWrite(in3, HIGH);
    digitalWrite(in4, LOW);
 
    //Determine Motor Speeds
 
   MotorSpeed1 = map(joyposVert, 564, 1023, 0, 255);
   MotorSpeed2 = map(joyposVert, 564, 1023, 0, 255); 

 
  }
  else
  {
    // This is Stopped
 
    MotorSpeed1 = 0;
    MotorSpeed2 = 0; 
 
  }
  
  // Now do the steering
  // The Horizontal position will "weigh" the motor speed
  // Values for each motor


 
  if (joyposHorz < 460)
  {
    // Move Left
 
    // As we are going left we need to reverse readings
 
    joyposHorz = joyposHorz - 460; // This produces a negative number
    joyposHorz = joyposHorz * -1;  // Make the number positive
 
    // Map the number to a value of 255 maximum
 
   joyposHorz = map(joyposHorz, 0, 460, 0, 255);

    
 
    MotorSpeed1 = MotorSpeed1 - joyposHorz;
    MotorSpeed2 = MotorSpeed2 + joyposHorz;
 
    // Don't exceed range of 0-255 for motor speeds
 
    if (MotorSpeed1 < 0)MotorSpeed1 = 0;
   if (MotorSpeed2 > 255)MotorSpeed2 = 255;

 
  }
  else if (joyposHorz > 564)
  {
    // Move Right
 
    // Map the number to a value of 255 maximum
 
   joyposHorz = map(joyposHorz, 564, 1023, 0, 255);

   
        
 
    MotorSpeed1 = MotorSpeed1 + joyposHorz;
    MotorSpeed2 = MotorSpeed2 - joyposHorz;
 
    // Don't exceed range of 0-255 for motor speeds
 
   if (MotorSpeed1 > 255)MotorSpeed1 = 255;
    
    if (MotorSpeed2 < 0)MotorSpeed2 = 0;      
 
  }
 
 
  // Adjust to prevent "buzzing" at very low speed
 
if (MotorSpeed1 < 10)MotorSpeed1 = 0;
 if (MotorSpeed2 < 10)MotorSpeed2 = 0;

 }
else if (switchValue==0) {

 
  digitalWrite(in1, HIGH);
  digitalWrite(in2, LOW);
  MotorSpeed1=150;
  // Motor B
  
 
  digitalWrite(in3, LOW);
  digitalWrite(in4, HIGH);
MotorSpeed2=150;
}
 
  // Set the motor speeds
 
  analogWrite(enA, MotorSpeed1);
  analogWrite(enB, MotorSpeed2);

   
Serial.print("X: ");
  Serial.print(MotorSpeed1);
   Serial.print(" Y: ");
  Serial.print(MotorSpeed2);
  Serial.print(" Button: ");
  Serial.println(switchValue);
  
 
}

 

Udostępnij ten post


Link to post
Share on other sites

To może dodaj zmienną, w której będziesz trzymać docelową prędkość danego silnika, osobną od aktualnej jego prędkości, i w każdym obrocie pętli, jeśli docelowa prędkość jest większa od aktualnej, to zwiększaj aktualną o jakąś ograniczoną od góry wartość, a jak jest mniejsza, to zmniejszaj, analogicznie.

Udostępnij ten post


Link to post
Share on other sites
(edytowany)
15 godzin temu, MarcinTe napisał:

chcialbym zeby po natychmiastowym wychyleniu do przodu predkosc nie skoczyla od razu do wartosci maksymalnej tylko chwile plynnie do niej dochodzila.

Prędkość zwiększaj w przerwaniu od timera.

Jak chcesz zrobić rampę to mam gdzieś kod źródłowy.

Edytowano przez InspektorGadzet

Udostępnij ten post


Link to post
Share on other sites

Dzieki za popdowiedzi, sprobuje potestowac z ograniczeniem predkosci o stala czasowa..

Nie wiem o co chodzi z ta rampa ale i tak poprosze o ten kod 🙂

Udostępnij ten post


Link to post
Share on other sites
30 minut temu, MarcinTe napisał:

Nie wiem o co chodzi z ta rampa ale i tak poprosze o ten kod

Nie wiesz a chcesz? Mam odczucie, że kod się nie przyda. Jest w dużym projekcie, wyciąłem istotne fragmenty, jak potrzebne coś jeszcze to napisz co konkretnie.

void Przesow( uint8_t stan )
{
  if ( stan ) {
		AktualnaMoc = 1;
		fazaRozpedu = ROZBIEG;
		KrokPrzyrostukMocy = (float)Cfg.silnik / Cfg.tRozpedzania;						// przyrost mocy na 1ms = (Vmax-Vmin / 500ms)
		uint8_t mocMin = 30;																									// Procentowa moc, do ktorej zwalniamy
		if( mocMin > Cfg.silnik ) mocMin = Cfg.silnik;
		KrokZmniejszaniaMocy = (float)(Cfg.silnik-mocMin) / Cfg.lHamowania;		// spadek predkosci w % na 0,1mm (Pmax-Pmin) / DYSTANS mm
		UstawMoc( AktualnaMoc );
    HAL_TIM_Base_Start_IT( &htim4 );// Start przerwan od timera
    TimEnkoder = DEF_TIMENKODER; FL_tstEnkoder = true;   // Wlaczenie kontroli enkodera
  }
  else {
    HAL_TIM_Base_Stop_IT( &htim4 );  // Stop timera
		HAL_GPIO_WritePin( STEP_GPIO_Port, STEP_Pin, GPIO_PIN_RESET );	// STEP (PWM) Konczymy zawsze poziomem niskim
    FL_koniecPrzesowu = true;
    FL_tstEnkoder = false;           // Wylaczenie kontroli enkodera
		FL_Enkoder = false;
//		hamulec( 0 );	// TimHamucec==1 zalatwia sprawe
  }
}


void TIM4_IRQHandler(void)
{
  /* USER CODE BEGIN TIM4_IRQn 0 */
	HAL_GPIO_TogglePin( STEP_GPIO_Port, STEP_Pin );

  /* USER CODE END TIM4_IRQn 0 */
  HAL_TIM_IRQHandler(&htim4);
  /* USER CODE BEGIN TIM4_IRQn 1 */

  /* USER CODE END TIM4_IRQn 1 */
}


//------------------------------------------------------------
char volatile FL_wykrytoZnacznik = false;
//------------------------------------------------------------
void wykrytyZnacznik()		// Zadzialala fotokomorka. Wykryte przez EXTI lub 1ms
{
	if( FL_wykrytoZnacznik ) return; 				// Jesli znacznik byl juz wykryty wyjdz

	FL_wykrytoZnacznik = true;
//	Przesow( false );											// Natychmiastowe zatrzymanie

	fazaRozpedu = HAMOWANIE;								// soft-stop
	TimSoftStop = CZAS_ZATRZYMANIA_Z_FOTO;
}


//------------------------------------------------------------
void ZwalnianieFoto()		// Wywolywane w przerwaniu 1ms
{
	if( (!TimSoftStop && FL_wykrytoZnacznik && Cfg.TrybPracy==1) ||
			(!TimSoftStop && FL_wykrytoZnacznik && Cfg.TrybPracy==2) )
			{
			TimSoftStop = 0xFFFF;
			Przesow( false );
			}
}


void PracaSilnika1ms()			// Wywolywane co 1ms w przerwaniu
{
int static volatile dobieg=0;


	switch( fazaRozpedu )
	{
		case ROZBIEG:
			if( AktualnaMoc <= (float)Cfg.silnik  )					// Jesli moc mniejsza od minimalnej
			{
			AktualnaMoc += KrokPrzyrostukMocy;
			UstawMoc( AktualnaMoc );
			}
			else{
				fazaRozpedu = BIEG;
      __NOP();
			}
			break;
		case BIEG:
			if( lenZmierzone/1000 > Cfg.len-Cfg.lHamowania ){		// Jesli zblizamy sie do konca materialu
				fazaRozpedu = HAMOWANIE;
				hamulec( Cfg.tHamulec );												// INFO: hamulec zwalniany przez "Przesow(" INFO: przez TimHamulec
			__asm{ NOP };
			}
			break;
		case HAMOWANIE:
				if( AktualnaMoc > 1 )	{
				AktualnaMoc -= KrokPrzyrostukMocy;
				UstawMoc( AktualnaMoc );
				}
			break;
	}
}

 

Udostępnij ten post


Link to post
Share on other sites

InspektorGadzet, faktycznie niewiele z tego rozumiem, wroce do tego kodu na pewno jak sie troche poducze, dziekuje za poswiecony czas i przepraszam za zaklocenia. Pozdrawiam

Udostępnij ten post


Link to post
Share on other sites
8 godzin temu, MarcinTe napisał:

faktycznie niewiele z tego rozumiem

Spodziewałem się tego. Nawet nie zauważyłeś, że kod jest dla STM32 i używa HAL.

Możesz pokazać fotografie jak rozwiązałeś napęd i jak zabezpieczyłeś sterownik przez wpływami atmosferycznymi? W wózku to chyba IP 67 musi być? Zgadza się?

Udostępnij ten post


Link to post
Share on other sites

InspektorGadzet, dzieki za zainteresowanie ale za rada kolegi na innym forum chyba sobie odpuszcze to przedsiewziecie, widze ze mnie zdecydowanie przerasta. Pozdrawiam

Udostępnij ten post


Link to post
Share on other sites
1 godzinę temu, MarcinTe napisał:

odpuszcze to przedsiewziecie, widze ze mnie zdecydowanie przerasta.

Jest powiedzenie (przysłowie?) "Mierz siły na zamiary".

Jesteś początkujący, co widać po problemie, który masz a wybrałeś sobie ambitne, jak na swoje możliwości zadanie. Zacznij od czegoś prostszego, może samochód zdalnie sterowany? Dzięki temu zapoznasz się z problemami jakie występują przy sterowaniu silników.

Udostępnij ten post


Link to post
Share on other sites

To moze jeszcze tylko dopytam na czym docelowo realizuje sie takie projekty, bo rozumiem ze nie na Arduino? 

Udostępnij ten post


Link to post
Share on other sites

Moc obliczeniowa Arduino spokojnie wystarczy do sterowania wózkiem. Znam bardziej skomplikowane projekty ,(sterowanie głosem) oparte na RPi.

Tu jednak najważniejsze jest bezpieczeństwo. Pomyśl, co się stanie jeśli jakiś drucik wsadzony w gniazdo w Arduino uzna za stosowne wysunąć się np. w trakcie wjazdu na krawężnik...

 

Udostępnij ten post


Link to post
Share on other sites
(edytowany)
1 godzinę temu, ethanak napisał:

Moc obliczeniowa Arduino spokojnie wystarczy do sterowania wózkiem

Pod warunkiem, że użyje się sprzętu a nie, jak to mówią (piszą) "machanie pinem" a w tym kodzie tak prawdopodobnie jest. Autor nie dołączył kodu bibliotek, ale one dają możliwość generowania sygnału na dowolnym pinie. To oznacza, że nie korzystają ze sprzętu, a to oznacza, że są ułomne.

 

Edytowano przez InspektorGadzet

Udostępnij ten post


Link to post
Share on other sites

Możesz jakoś rozwinąć owo niewątpliwie twórcze stwierdzenie? Szczególnie interesujące jest tu owo "niekorzystanie ze sprzętu"...

Udostępnij ten post


Link to post
Share on other sites
(edytowany)
19 minut temu, ethanak napisał:

Możesz jakoś rozwinąć owo niewątpliwie twórcze stwierdzenie? Szczególnie interesujące jest tu owo "niekorzystanie ze sprzętu"...

Nie analizuję każdej biblioteki Arduino (używam  ARM, głównie STM32 często LPC od NXP), bo te co analizowałem (jest ich dziesiątki tysięcy), używają millis, programowych SPI, I2C, UART. Jakiej użył autor tego wątku? Nie wiadomo? Przykładowo pod nazwą  "onewire" są biblioteki akceptowalne i nieakceptowalne. Takich, które używają rozwiązań zalecanych przez producenta (Dallas, teraz Dallas-Maxim) nie widziałem. Nie oznacza to, że takich nie ma, ale na forach widzę tylko "machanie pinem".

Analizowałem biblioteki graficzne U8 (coś tam dalej w nazwie). Tragedia! Moja kostka wyświetlałaby obrazek poi kilku sekundach! Co gorsza, byłoby widać jego rysowanie! Próbowałem te biblioteki z 320x240 SPI. Szkoda pisać, to trzeba zobaczyć. Wczytanie i wyświetlenie BMP to 2,5 sekundy. Dopiero na ARM, do LCD DMA, do karty SDIO (4-bit), daje zadowalające efekty.

 

Edytowano przez InspektorGadzet

Udostępnij ten post


Link to post
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Gość
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.


×
×
  • Utwórz nowe...