• 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
Camera Slider sterowany przez Bluetooth
#1
Mój poprzedni wątek dot.sterowania sliderem prze bluetooth został szybko zamknięty przez moderatora. Ale moje problemy się nie skończyły.
Otóż nie mogę uruchomić funkcji pan() po poprawnym wprowadzeniu danych przez bluetooth. Wszystkie niezbędne parametry do poprawnego działania tej funkcji  (Lkp,Lko,Prp,Pro)są poprawne. Dla testu dałączyłem dwie proste funkcje led1() i led2() i te działają.
Oto kod:
Kod:
//#include <String.h>
#include <AccelStepper.h>
#include <MultiStepper.h>
#define buffsize 32

char input[buffsize];
uint16_t dane [10]; // jakie i ile  zmiennych odbieramy z UART
byte index = 0;
boolean stringComplete = false;  // gdy cale polecenie/napis odebrany
long ng =  0 ; // Czas nagrywania (godziny)       
long nm =  0 ; // Czas nagrywania (minuty)       
long ns =  0  ; // Czas nagrywania (sekundy)
long Dp = 0;
long so = 0;
long Kog = 0;
long Kp = 0;
long Ko = 0;
long Cp = 0;
long A;
int x = 0;
long Lkp;
long Lko ;
long Prp;
long Pro;

AccelStepper stepper1 (1, 2, 5); //shield V3
AccelStepper stepper2 (1, 3, 6);
const int enablePin1 = 8; // Steruje wyłączaniem sterowników
const int enablePin2 = 8;
MultiStepper steppersControl; 
long gotoposition[3];
void   parsujpolecenia()
  {
    //polecenie ma wygladac tak: cmd=zmienna1,zmienna2,zmienna3,zmienna4  z zalozenia sa to 4 liczby calkowite
    // do 5 cyfr, dlatego buffsize32 ma zapas, dla innych trzeba zmodyfikowac bufor, tablice zmiennych, funkcje
    // do konwersji napisu na liczby
    //cmd=234,342,553,3432
   
     uint8_t index=0;
    char * polecenie=input;
    Serial.print("Otrzymane polecenie: ");
    Serial.println(polecenie);

    char* command1 = strtok(polecenie, "=");

if (strcmp(command1 , "cmd")==0){  //sprawdzenie czy czesc przed znakiem = jest rowna cmd
while (command1 != 0)
{
//Serial.println(command1);
command1 = strtok(NULL, ","); //dzielimy reszte napisu w miejscach gdzie jest ","

// Znajdź następne polecenie w ciągu wejściowym
if(index<10) dane[index]=atoi(command1); //konwersja napisu na INT i zapisanie do kolejnej pozycji w tablicy
index++;
A = dane[0];
Dp = dane[1];
Kog = dane[2];
ng = dane[7];
nm = dane[8];
ns = dane[9];
Kp = dane[3];
Ko = dane[4];
so = dane[6];
Cp = dane[5];


}
}
  else 
  Lkp = Dp*80*10;
  const long Lkp = dane[1]*80*10;
const long Lko = Kog*3*8.8889; //8.8889 dla 16 kroków
const long Prp = Lkp/Cp  ; // Prędkość w poziomie( kroki/sek)
const long Pro = Lko/Cp  ; //Prędkość głowicy( kroki/sek)

 
  Serial.println("Polecenie nieprawidlowe");
  Serial.println("Aktualne parametry:");
  Serial.print(" A = ");
  Serial.println(A);
  Serial.print(" Dp = ");
  Serial.println(Dp);
  Serial.print(" Cp = ");
  Serial.println(Cp);
  Serial.print(" Kog = ");
  Serial.println(Kog);
  Serial.print(" Kp = ");
  Serial.println(Kp);
  Serial.print(" Ko = ");
  Serial.println(Ko);
  Serial.print(" ng = ");
  Serial.println(ng);
  Serial.print(" nm = ");
  Serial.println(nm);
  Serial.print(" ns = ");
  Serial.println(ns); 
  Serial.print(" so = ");
  Serial.println(so);
  Serial.print(" Lko = ");
  Serial.println(Lko);
  Serial.print(" Pro = ");
  Serial.println(Pro);
  Serial.print(" Lkp = ");
  Serial.println(Lkp);
  Serial.print(" Prp = ");
  Serial.println(Prp);

    stringComplete = false;
  }
  // Arduino initialization function.
void setup()
{
  Serial.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(enablePin1,OUTPUT);
  pinMode(enablePin2,OUTPUT);

  stepper1.setMaxSpeed(Prp);
  stepper2.setMaxSpeed(Pro);
  steppersControl.addStepper(stepper1);
  steppersControl.addStepper(stepper2);
 
}
void loop()
{
if (stringComplete) parsujpolecenia();
// Teraz mozna cos zrobic ze zmiennymi
delay(1000);
switch (A)
   {
    case 0:
     pan();
     led1();
      break;
    case 1:
    pan();
       led2();
      break;
    //default:
      // instrukcje domyślne (jeżeli var różne od 1 i 2)
  }

}
void serialEvent() {
  while (Serial.available()>0) {
char aChar = Serial.read();
     if(aChar == '\n')
     {
       // wykryto znak konca linii \n, koniec odbioru
       input[index] = 0;
       index = 0;
       stringComplete = true;
     }
     else
     {
        input[index] = aChar;
        if(index<buffsize) index++;
        input[index] = '\0'; // Na koncu napisu wstawiamy 0   
     }
  }
}
void pan()
{
  gotoposition[0] = Lkp;  // 800 steps - full rotation with quater-step resolution
  gotoposition[1] = Lko;


  steppersControl.moveTo(gotoposition); // Calculates the required speed for all motors
  steppersControl.runSpeedToPosition(); // Blocks until all steppers are in position
}
void led1()
{ digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);                       // wait for a second
  digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);
  }
  void led2()
{ digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(100);                       // wait for a second
  digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
  delay(100);
  }
Gdzie tkwi błąd?
Do obsługi slidera stworzyłem taką apkę:

https://ai2.appinventor.mit.edu/b/1pj7q
 
Odpowiedź
#2
Jak chcesz by aplikacja mogła reagować na polecenia z zewnątrz to wywal delay, naucz się millis, to proste jak się przestawisz z zatrzymywania poleceń na omijanie ich. Na pewno za mały bufor, jak chcesz wysyłać 10 zmiennych uint16 to one mają do 5 znaków każda, przecinki, cmd, tak na oko to 70 znaki co najmniej, znak końca linii, potem sobie robisz jeszcze z tego zmienne long, jak nie potrzebujesz to zostań przy uint16_t, jak ze znakiem to int16_t. Masz zresztą w komentarzu, że buffsize 32 to dla 4 liczb.
Miło być decenianym https://buycoffee.to/kaczakat
 
Odpowiedź
#3
Dziękuję za odpowiedź. Niestety, ze względu na moją znikomą wiedzę programistyczną niewiele z tego zrozumiałem i nie wiem jakie zmiany wprowadzić. A mój wiek (70l) nie sprzyja już nauce. Rzeczywiście, gdy zastąpiłem zmienne (Lkp,Lko,Prp,Pro) liczbami to zaskoczyło. Próbowałem zapisać buffsize 32 i unit32_t, ale bez efektu.Byłbym zobowiązany gdybyś mógł nanieść w tym kodzie odpowiednie poprawki.
 
Odpowiedź
#4
Każda literka przysyłana z BT to 1 bajt, literka czyli znak abCD1%#, jak wysyłasz 10 zmiennych linią cmd=12345,12345,12345..../n to wszystkie musisz zliczyć dla najmniej korzystnego wariantu i zabezpieczyć miejsce w tablicy znaków na cały ciąg tych literek, np. na 70 znaków:
#define buffsize 70
bo tu tworzysz tablicę o tej wielkości na literki:
char input[buffsize];
Z millis masz przykład w Arduino, zaczynasz od migania led, potem dwoma i tak wszystko co się nauczyłeś do tej pory robisz od nowa bez delay używając millis. Bez tego bardziej rozbudowane programy zawsze będą kulawe. Np. chcesz migać jedną led co 2s, a drugą co 350ms i to Ci się nigdy nie uda. Obie będą migać, ale nie tak jak to sobie zaplanowałeś, zawsze największy delay zakłoci działanie mniejszych drastycznie, mniejsze większym wprowadzą błąd.
Miło być decenianym https://buycoffee.to/kaczakat
 
Odpowiedź
#5
(24-10-2024, 16:03)andrzejn napisał(a): Mój poprzedni wątek dot.sterowania sliderem prze bluetooth został szybko zamknięty przez moderatora. Ale moje problemy się nie skończyły.


Masz taki kawałek kodu:

Kod:
if (strcmp(command1 , "cmd")==0){  //sprawdzenie czy czesc przed znakiem = jest rowna cmd
while (command1 != 0)
{
//Serial.println(command1);
command1 = strtok(NULL, ","); //dzielimy reszte napisu w miejscach gdzie jest ","

// Znajdź następne polecenie w ciągu wejściowym
if(index<10) dane[index]=atoi(command1); //konwersja napisu na INT i zapisanie do kolejnej pozycji w tablicy
index++;
A = dane[0];
Dp = dane[1];
Kog = dane[2];
ng = dane[7];
nm = dane[8];
ns = dane[9];
Kp = dane[3];
Ko = dane[4];
so = dane[6];
Cp = dane[5];
}
}

Jest tu kilka problemów - najpierw sprawdzasz zmienną (w instrukcji while) a potem ją podstawiasz - jak dostaniesz ostatni element to strtok zwróci NULL a pojedziesz dalej. Proponuje od razu strtok umieścic w warunku while,
Kod:
if (strcmp(command1 , "cmd")==0)

    while ((command1 = strtok(NULL, ",")) != NULL)
    {
        // Znajdź następne polecenie w ciągu wejściowym
        dane[index++]=atoi(command1); //konwersja napisu na INT i zapisanie do kolejnej pozycji w tablicy
        if (index == (sizeof(dane)/sizeof(dane[0])))
            break;
    }
    // tutaj te przepisania do zmiennych
}

Warto też ten szereg podstawien przesunąć poza pętle - po co je wykonywac wiele razy.
 
Odpowiedź
#6
Doszedłem do wniosku, że wystarczą mi tylko 4 zmienne niezbędne do uruchomienia pan(). Zmieniłem zatem kod uwzględniając również sugestie oscarX.
Kod:
//#include <String.h>
#include <AccelStepper.h>
#include <MultiStepper.h>
#define buffsize 32

char input[buffsize];
uint16_t dane [4]; // jakie i ile  zmiennych odbieramy z UART
byte index = 0;
boolean stringComplete = false;  // gdy cale polecenie/napis odebrany

long Lkp;
long Lko ;
int Prp;
int Pro;


AccelStepper stepper1 (1, 2, 5); //shield V3
AccelStepper stepper2 (1, 3, 6);
const int enablePin1 = 8; // Steruje wyłączaniem sterowników
const int enablePin2 = 8;
MultiStepper steppersControl; 
long gotoposition[3];
void   parsujpolecenia()
  {
    //polecenie ma wygladac tak: cmd=zmienna1,zmienna2,zmienna3,zmienna4  z zalozenia sa to 4 liczby calkowite
    // do 5 cyfr, dlatego buffsize32 ma zapas, dla innych trzeba zmodyfikowac bufor, tablice zmiennych, funkcje
    // do konwersji napisu na liczby
    //cmd=234,342,553,3432
   
     uint8_t index=0;
    char * polecenie=input;
    Serial.print("Otrzymane polecenie: ");
    Serial.println(polecenie);

    char* command1 = strtok(polecenie, "=");

if (strcmp(command1 , "cmd")==0)
{
    while ((command1 = strtok(NULL, ",")) != NULL)
    {
        // Znajdź następne polecenie w ciągu wejściowym
        dane[index++]=atoi(command1); //konwersja napisu na INT i zapisanie do kolejnej pozycji w tablicy
        if (index == (sizeof(dane)/sizeof(dane[0])))
            break;
}
   Lkp = dane[0];
   Lko = dane[1];
   Prp = dane[2];
   Pro = dane[3];
}
  else   
  Serial.println("Polecenie nieprawidlowe");
  Serial.println("Aktualne parametry:");
  Serial.print(" Lkp = ");
  Serial.println(Lkp);
  Serial.print(" Lko = ");
  Serial.println(Lko);
  Serial.print(" Prp = ");
  Serial.println(Prp);

  Serial.print(" Pro = ");
  Serial.println(Pro);

    stringComplete = false;
  }
  // Arduino initialization function.
void setup()
{
  Serial.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(enablePin1,OUTPUT);
  pinMode(enablePin2,OUTPUT);

  stepper1.setMaxSpeed(Prp);
  stepper2.setMaxSpeed(Pro);
  steppersControl.addStepper(stepper1);
  steppersControl.addStepper(stepper2);
 
}
void loop()
{
if (stringComplete) parsujpolecenia();
// Teraz mozna cos zrobic ze zmiennymi
pan();
}
void serialEvent() {
  while (Serial.available()>0) {
char aChar = Serial.read();
     if(aChar == '\n')
     {
       // wykryto znak konca linii \n, koniec odbioru
       input[index] = 0;
       index = 0;
       stringComplete = true;
     }
     else
     {
        input[index] = aChar;
        if(index<buffsize) index++;
        input[index] = '\0'; // Na koncu napisu wstawiamy 0   
     }
  }
}
void pan()
{
   
  gotoposition[0] = Lkp;  // 800 steps - full rotation with quater-step resolution
  gotoposition[1] = Lko;

  steppersControl.moveTo(gotoposition); // Calculates the required speed for all motors
  steppersControl.runSpeedToPosition(); // Blocks until all steppers are in position

}
Wielokrotnie manipulowałem rozmiarem buffsize, ale bez efektu. Natomiast każde zastąpienie zmiennych liczbami poprawnie uruchamia funkcję pan().
Jest jeszcze jedna kwestia. Używam biblioteki Multistepper.h i nie potafię zmienić kierunku obrotu silników.
 
Odpowiedź
#7
Nie wiem jakie miałeś dane wejściowe, funkcja do konwersji ciągu znaków jest tylko do int, a Ty sobie tam wstawiałeś też long, jak przekroczysz zakres zmiennych to będziesz miał dziwne efekty, zastanów się czy potrzebujesz liczby większej niż 65 tysięcy. Ewentualnie zastąp atoi odpowiednią funkcją dla long.
Kierunek obrotów przetestuj na osobnym programie, może masz coś źle podłączone, shield to pewnie jakiś driver, biblioteka powinna zmieniać stan pinu dir drivera.
Miło być decenianym https://buycoffee.to/kaczakat
 
Odpowiedź
#8
Moja prowadnica slidera ma 85 cm, co przy 80 krokach/mm daje 68 000. Ostatecznie mogę używać długości do 81 cm.
 Zamieniłem wszystkie zmienne na int i też nie pomogło.
Jeśli chodzi o kierunek obrotu silników to właśnie nie wiem jak przy użyciu Multistepper.h powinien wygłądać zapis ustalający kierunek
 
Odpowiedź
#9
Patrząc na kod widzę, że w funkcji setup ustawiasz oba maxSpeed-y na wartości nieustalone - te zmienne jeszcze nie są ustawione. W loop też robisz podobnie - przecież pierwsze wejście do tej funkcji nie zastanie jeszcze polecenia z parametrami i właściwe zmienne nie zostaną ustawione (są globalne, więc kompilator ustawi na zero).
Jak chcesz robić synchronicznie to wszystko - na polecenie też powinieneś czekać.
Nie bardzo też widzę jak czytasz dane z seriala - ta funkcja serialEvent to ma być na przerwaniu wołana? Bo nigdzie nie widzę jej wywołania.
Ta twoja funkcja loop to powinna wyuglądać mniej więcej tak:
Kod:
void loop()

{
    while (stringComplete == 0)
        serialEvent();
    parsujpolecenia();

    // Teraz mozna cos zrobic ze zmiennymi

    pan();
}
Wtedy jedno  wejście do loop będzie czytać i realizować jedno polecenie. Rozpoczętego ruchu już nie da się przerwać - będzie musiał dojść do końca i dopiero będzie gotowy na następne polecenie.
 
Odpowiedź
#10
Spoko, ale może nie potrzebujesz poruszać się z dokładnością 1/80mm, możesz poruszać się w krokach 0.8mm i wtedy potrzebujesz wysłać wartość od 0-6800, z tego zrobić rzutowanie na int32 x10 i taki argument wstawić do programu, czyli np. 3456 wysłany przez BT do uC będzie pozycją dla krokowca 34560.
W poprzednim wątku kaczakat wyjaśniał, że jeśli to jest UNO/NANO to serialEvent jest zaszyty w loop, jeśli jest to ESP to trzeba dodać linię z wywołaniem tej funkcji.
 
Odpowiedź
  


Skocz do:


Przeglądający: 1 gości