Skocz do zawartości

Prosty "komputer" do ciągnika lub kombajnu --Boardinformator.


Pomocna odpowiedź

Cześć wszystkim.

Jako iż projekt który zacząłem prawie rok temu powoli idzie do przodu uznałem, że założę oddzielny temat. Wcześniejsze wpisy można przeczytać w tym temacie

Otóż postanowiłem stworzyć urządzenie, które będzie wskazywać prędkość jazdy, obroty W.P.M., obliczać chwilową wydajność i liczyć przejazdy maszyny na podstawie uniesień trójpunktowego układu zawieszenia narzędzi. Z tego zliczania wyszła jeszcze funkcja załączania w odpowiednim momencie ścieżek technologicznych w siewniku. Wszystko miało być oparte o proste menu w którym moglibyśmy wprowadzać szerokość zagregowanej maszyny, wprowadzać obwód koła aby prawidłowo zliczało prędkość i ustawiać "cykl" zliczania i załączania wcześniej wspomnianych ścieżek technologicznych. Jako wyświetlacz do urządzenia wybrałem 20x4 LCD a do sterowania prostą klawiaturę 4x1.

I tak zaczynając najpierw od dwóch zapisanych kartek z tym jak to sobie wyobrażam.BC2.jpg.2d0a7227070c2b9784c9a067af1a2d3d.thumb.jpg.6e0d8d652d712d5ea020743d70842a87.jpgBC1.jpg.ec226f9a1373b5477937ed7b604542e8.thumb.jpg.ce7e4b97d6625876ec5554c942c55d69.jpg

Powstało coś co wyglądało tak obraz_2024-01-10_221543697.thumb.png.fcfe8e3b24ca7ea72e33a95fb61e6fcf.png a TUTAJ link do działania tego urządzenia. Oczywiście ta obudowa z pudełka jest tymczasowa i służy do testowania tego co napiszę w warunkach domowych.

I tak dodając kolejne funkcjonalności takie jak opóźnienie zliczania przejazdów, załączanie siłownika liniowego i reset przejazdów w odpowiednim momencie przyszedł czas aby klawisze zamienić na docelowe czujniki a diody na siłownik. I tak na chwilę obecną otrzymałem coś co zaczyna wyglądać tak jak to sobie wyobraziłem. Zaczynam pierwsze testy na stole z czujnikami indukcyjnymi i siłownikiem liniowym. Oczywiście już widzę, że wykorzystanie while() spowodowało, że urządzenie reaguje z opóźnieniem jak również będzie trzeba zastosować jakiś lcd.clear() do odświeżania wyświetlanych informacji. No i oczywiście pora przenosić wszystko z płytki stykowej na drukowaną uniwersalną a obudowę zrobić z puszki instalacyjnej.

A tutaj kilka zdjęcie i FILM jak to teraz wygląda.IMG_20240110_222344_197.thumb.jpg.99d0476ac8c01701d9a58dfaa9ad1c8b.jpg

Pierwsze prace aby wyjść z tego makaronu.

IMG_20240111_115942_596_LL.thumb.jpg.96c72363ed44acd18649b24d430085f9.jpg

Ktoś testował jak bardzo można wydłużyć przewody pomiędzy wyświetlaczem 20x4 LCD z i2c a płytką Arduino? Bo naszła mnie myśl aby był w osobnej obudowie.

Edytowano przez Adonaktiv
Dodanie zdjęć.
Link do komentarza
Share on other sites

(edytowany)

Jeżeli chodzi o odświeżanie danych na LCD to zrób sobie kopie zmiennych tych danych i w warunku sprawdzaj czy dane się zmieniły, jeśli tak to odswiezasz...cos w stylu.. 

int kopia_predkosc;
int predkosc = analogRead(4); 

if (predkosc != kopia_prędkość) { 
  kopia_predkosc = prędkość; 
  //ustaw kursor 
  //wyswietl zmienna prędkość 
}

Ps..co do opóźnienia spowodowanego przez pętlę while() to coś musiałeś błędnie założyć, stąd to opóźnienie, przy prawidłowym warunku nie ma opcji żeby były opóźnienia...pokaż kod to doradzimy

Edytowano przez farmaceuta
Link do komentarza
Share on other sites

(edytowany)

Kod wygląda tak

/*..................................................
..       projek     BOARDINFORMATOR               ..
....................................................
*/

/*..................................................
..  zmienne+przypisanie pin                       ..
....................................................
*/
#include <EasyButton.h>
#include <Timers.h>
#include <LiquidCrystal_I2C.h>
#include <Wire.h>

#define BTN_OK 13
#define BTN_PREV 12
#define BTN_BACK 11
#define BTN_NEXT 10
#define KOLO 8
#define WOM 3
#define cTUZ 4
#define DcLeft 6
#define DcRight 5

EasyButton NEXT(BTN_NEXT);
EasyButton PREV(BTN_PREV);
EasyButton OK(BTN_OK);
EasyButton BACK(BTN_BACK);

LiquidCrystal_I2C lcd(0x27, 20, 4);
Timer timer;
int AktPrz = 1;     // aktualny przejazd
float SzerRob = 3;  // szer robocza narzędzia
bool ScTech = 0;    // sciezki czy włączone
int SzSc = 4;       // szerokosc sciezki
int KiedSc = 4;     // w ktorym przejazdzie sciezka
float ObKo = 5.28;  // obwod koła
int Imp = 8;        //ile impulsow na obrot koła
int Op = 10;       // opuznienie imp tuz
int volatile A = 0;
float kph = 0;
float hah = 0;
int rpm = 0;
const unsigned long sampleTime = 5000;
unsigned long rwdole = 0;
unsigned long rwgorze = 0;
boolean ramiona = LOW;

void setup() {
  lcd.begin(20, 4);
  lcd.init();
  lcd.backlight();


  NEXT.begin();
  PREV.begin();
  OK.begin();
  BACK.begin();
  pinMode(cTUZ, INPUT_PULLUP);
  pinMode(WOM, INPUT_PULLUP);
  pinMode(KOLO, INPUT_PULLUP);
  pinMode(DcRight, OUTPUT);
  pinMode(DcLeft, OUTPUT);
}


void loop() {

  //DEFINICJE KLAWISZY
  NEXT.read();
  PREV.read();
  OK.read();
  BACK.read();
  getAktPrz();
  Menu_Glowne();
  Sciezki();
}
/*...............................................................................................
..                                         FUNKCJE                                             ..
..                                                                                             ..
.................................................................................................
*/


/*.........................................................
..   INSTRUKCJA SWITH DZIĘKI KTÓREJ UTWORZONO MENU       ..
..                                                       ..
...........................................................
*/


void Menu_Glowne() {

  switch (A) {
    case 0:
      BoardComputer1();
      Nastepny_Ekran();
      break;

    case 1:
      BoardComputer2();
      Nastepny_Ekran();
      Poprzedni_Ekran();

      break;

    case 2:
      Menu_1();
      Nastepny_Ekran();
      Poprzedni_Ekran();

      break;

    case 3:
      Menu_2();
      Nastepny_Ekran();
      Poprzedni_Ekran();

      break;

    case 4:
      Menu_3();
      Nastepny_Ekran();
      Poprzedni_Ekran();

      break;

    case 5:
      Menu_4();
      Nastepny_Ekran();
      Poprzedni_Ekran();


      break;

    case 6:
      Menu_5();
      Nastepny_Ekran();
      Poprzedni_Ekran();


      break;

    case 7:
      Menu_6();
      Nastepny_Ekran();
      Poprzedni_Ekran();

      break;

    case 8:
      Menu_7();
      Nastepny_Ekran();
      Poprzedni_Ekran();

      break;

    case 9:
      Menu_8();
      Poprzedni_Ekran();

      break;
  }
}
/*..................................................
..           PREDKOSC                             ..
....................................................
*/
float getKPH() {
  int impuls = 0;
  boolean kolo = LOW;
  unsigned long currentTime = 0;
  unsigned long startTime = millis();
  while (currentTime <= sampleTime & OK.isReleased()) {
    if (digitalRead(KOLO) == HIGH && kolo == HIGH) {
      impuls++;
      kolo = LOW;
    }
    if (digitalRead(KOLO) == LOW) {
      kolo = HIGH;
    }
    currentTime = millis() - startTime;
  }  
  float kph = ((impuls * (ObKo / Imp)) * 720) / 1000;
  return kph;
}
/*..................................................
..           HEKTARY                              ..
....................................................
*/
float getHAH() {
  if (digitalRead(cTUZ) == HIGH) {
  float hah = ((kph * 1000) * SzerRob) / 10000;
  return hah;
  }
  }

/*..................................................
..          WOM                                   ..
....................................................
*/
float getWOM() {

  unsigned long currentTime1 = 0;
  unsigned long startTime1 = millis();
  int obrot = 0;
  boolean wom = LOW;
  while (currentTime1 <= sampleTime & OK.isReleased()) {
    if (digitalRead(WOM) == LOW && wom == LOW) {
      wom = HIGH;
      obrot++;
    }
    if (digitalRead(WOM) == HIGH) {
      wom = LOW;
    }
    currentTime1 = millis() - startTime1;
  }

  int rpm = (60000. / float(sampleTime)) * obrot;
  return rpm;
}


/*..................................................
..               LICZNIK PRZEJAZDÓW               ..
....................................................
*/

int getAktPrz() {
  
  if (digitalRead(cTUZ) == LOW && ramiona == LOW) {
    rwgorze = millis();
  if (rwgorze >= rwdole + Op * 1000) {
    AktPrz = AktPrz + 1;
    ramiona = HIGH;
  }
}
  if (digitalRead(cTUZ) == HIGH ) {
    rwdole = millis();
    ramiona = LOW;
  }

       return AktPrz;  
}

/*..................................................
..           STEROWANIE SILNIKIEM SCIEZEK         ..
....................................................
*/

void Sciezki(){
  if (AktPrz == KiedSc){
    digitalWrite(DcLeft, HIGH);
    digitalWrite(DcRight, LOW);
  }
  if (AktPrz != KiedSc){
    digitalWrite(DcLeft, LOW);
    digitalWrite(DcRight, HIGH);
    if(AktPrz > SzSc){
      AktPrz = 1;
    }
  }
}


/*..................................................
..             BoardComputer1                     ..
....................................................
*/
void BoardComputer1() {
  lcd.setCursor(0, 0);
  lcd.print("Predkosc");
  lcd.setCursor(0, 1);
  lcd.print(kph);
  lcd.setCursor(5, 1);
  lcd.print("km/h");

  lcd.setCursor(0, 2);
  lcd.print("Wydajnosc");
  lcd.setCursor(0, 3);
  lcd.print(hah);
  lcd.setCursor(5, 3);
  lcd.print("ha/h");

  lcd.setCursor(15, 0);
  lcd.print("WOM");
  lcd.setCursor(13, 1);
  lcd.print(rpm);
  lcd.setCursor(17, 1);
  lcd.print("RPM");

  lcd.setCursor(13, 2);
  lcd.print("Sciezka");
  lcd.setCursor(13, 3);
  lcd.print(AktPrz);
  lcd.setCursor(15, 3);
  lcd.print("Z");
  lcd.setCursor(17, 3);
  lcd.print(SzSc);
  kph = getKPH();
  hah = getHAH();
  rpm = getWOM();
}
  
/*..................................................
..              BoardComputer2                    ..
....................................................
*/
void BoardComputer2() {
  lcd.setCursor(0, 0);
  lcd.print("BD");
  lcd.setCursor(0, 1);
  lcd.print(0);
  lcd.setCursor(6, 1);
  lcd.print("km/h");

  lcd.setCursor(0, 2);
  lcd.print("BD");
  lcd.setCursor(0, 3);
  lcd.print(0);
  lcd.setCursor(6, 3);
  lcd.print("ha/h");

  lcd.setCursor(15, 0);
  lcd.print("BD");
  lcd.setCursor(13, 1);
  lcd.print(0);  //
  lcd.setCursor(17, 1);
  lcd.print("RPM");

  lcd.setCursor(13, 2);
  lcd.print("BD");
  lcd.setCursor(15, 3);
  lcd.print(0);
}


/*..................................................
..      KOLEJNY        EKRAN                      ..
....................................................
*/
int Nastepny_Ekran() {
  if (OK.wasPressed()) {
    A++;
    lcd.clear();
  }
  return A;
}
/*..................................................
..      POPRZEDNI        EKRAN                    ..
....................................................
*/
int Poprzedni_Ekran() {
  if (BACK.wasPressed()) {    
    A--;
    lcd.clear();
  }
  return A;
}
/*..................................................
..         MENU1                                  ..
....................................................
*/
int Menu_1() {
  lcd.home();
  lcd.setCursor(0, 0);
  lcd.print("Aktualny przejazd");
  lcd.setCursor(0, 1);
  lcd.print(AktPrz);  // z czuj tuz
  if (NEXT.wasReleased()) {
    AktPrz = AktPrz + 1;
  }
  if (PREV.wasReleased()) {
    AktPrz = AktPrz - 1;
  }
  return AktPrz;
}

/*..................................................
..         MENU2                                  ..
....................................................
*/
float Menu_2() {
  lcd.home();
  lcd.setCursor(0, 0);
  lcd.print("Szer robocza");
  lcd.setCursor(0, 1);
  lcd.print(SzerRob);
  lcd.setCursor(10, 1);
  lcd.print("m");
  if (NEXT.wasReleased()) {
    SzerRob = SzerRob + 0.05;
  }
  if (PREV.wasReleased()) {
    SzerRob = SzerRob - 0.05;
  }
  return SzerRob;
}
/*..................................................
..         MENU3                                  ..
....................................................
*/
int Menu_3() {
  lcd.home();
  lcd.setCursor(0, 0);
  lcd.print("Czy sciezki aktywne");
  lcd.setCursor(0, 1);
  lcd.print(ScTech);
  lcd.setCursor(10, 1);
  if (NEXT.wasReleased()) {
    ScTech = ScTech = 1;
  }
  if (PREV.wasReleased()) {
    ScTech = ScTech = 0;
  }
  return ScTech;
}
/*..................................................
..         MENU4                                  ..
....................................................
*/
int Menu_4() {
  lcd.home();
  lcd.setCursor(0, 0);
  lcd.print("Szerokosc sciezki");
  lcd.setCursor(0, 1);
  lcd.print(SzSc);
  if (NEXT.wasReleased()) {
    SzSc = SzSc + 1;
  }
  if (PREV.wasReleased()) {
    SzSc = SzSc - 1;
  }
  return SzSc;
}
/*..................................................
..         MENU5                                  ..
....................................................
*/
int Menu_5() {
  lcd.home();
  lcd.setCursor(0, 0);
  lcd.print("Przejazd sciezki");
  lcd.setCursor(0, 1);
  lcd.print(KiedSc);
  if (NEXT.wasReleased()) {
    KiedSc = KiedSc + 1;
  }
  if (PREV.wasReleased()) {
    KiedSc = KiedSc - 1;
  }
  return KiedSc;
}
/*..................................................
..         MENU6                                  ..
....................................................
*/
float Menu_6() {
  lcd.home();
  lcd.setCursor(0, 0);
  lcd.print("Obwod kola");
  lcd.setCursor(0, 1);
  lcd.print(ObKo);
  lcd.setCursor(10, 1);
  lcd.print("m");
  if (NEXT.wasReleased()) {
    ObKo = ObKo + 0.05;
  }
  if (PREV.wasReleased()) {
    ObKo = ObKo - 0.05;
  }
  return ObKo;
}
/*..................................................
..         MENU7                                  ..
....................................................
*/
int Menu_7() {
  lcd.home();
  lcd.setCursor(0, 0);
  lcd.print("Ile IMP na obrot");
  lcd.setCursor(0, 1);
  lcd.print(Imp);
  lcd.setCursor(10, 1);
  lcd.print("m");
  if (NEXT.wasReleased()) {
    Imp = Imp + 1;
  }
  if (PREV.wasReleased()) {
    Imp = Imp - 1;
  }
  return Imp;
}
/*..................................................
..         MENU8                                  ..
....................................................
*/
int Menu_8() {
  lcd.home();
  lcd.setCursor(0, 0);
  lcd.print("Opuznienie zliczania");
  lcd.setCursor(0, 1);
  lcd.print(Op);
  lcd.setCursor(10, 1);
  lcd.print("sec");
  if (NEXT.wasReleased()) {
    Op = Op + 5;
  }
  if (PREV.wasReleased()) {
    Op = Op - 5;
  }
  return Op;
}

Zamysł był taki aby prędkość i obroty były średnią z 5 sec.

Coś takiego udało mi się stworzyć.

1704989247905673979184630445197.thumb.jpg.22077c03beac9694f088eaf17c52333c.jpg

Edytowano przez Adonaktiv
Dodanie zdjęcia
Link do komentarza
Share on other sites

5s to trochę długo moim zdaniem...możesz też tak napisać kod że jakimś czujnikiem halla czy czymś podobnym zliczasz czas trwania stanu wysokiego i niskiego i po pełnym cyklu (jednym obrocie koła/wału) aktualizujesz dane..

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

Średnia z 5 sec dla prędkości i obrotów jest dla mnie akceptowalna. Tylko muszę jakoś to oddzielić od reszty bo teraz wszystko chodzi w tym 5sec cyklu.

I tutaj na pomoc przyjdzie chyba to co proponowałeś. W jednym miejscu będzie trzeba obliczać to wszystko a w drugim wyświetlać.

Z tym odświeżaniem to nie wiem czy się dobrze zrozumieliśmy. 

Mamy jakiś odczyt np:  156 obr i jak potem jest zanik impulsów to robi mi się na wyświetlaczu 056.

Udało się uruchomić pierwszą płytkę, trochę źle rozlokowałem elementy także do poprawy i tak bedzie. No i sama plytka jest nie do końca taka. Myślałem że każda otwór będzie oddzielny a tutaj wzdłuż lecą linie połączonych otworów.

IMG_20240111_182100_925_LL.thumb.jpg.e872a0a6f86d05b5603a9d51502edb32.jpg

Link do komentarza
Share on other sites

16 minut temu, Adonaktiv napisał:

 Tylko muszę jakoś to oddzielić od reszty bo teraz wszystko chodzi w tym 5sec cyklu.

 if (digitalRead(KOLO) == 1 && kolo) { 
   kolo = 0;
   impuls++;
   } 
 if (digitalRead(KOLO) == 0) { 
   kolo = 1; 
   }


 if (millis() - lasttime >= 5000) {
  lasttime = millis();
   //oblicz prędkość 
   impuls == 0;
   }

To tak mniej więcej...ale ten kod nie będzie dokładny w obliczeniu prędkości...bo koło nie kreci się z dużą częstotliwością 

 

25 minut temu, Adonaktiv napisał:

 

Z tym odświeżaniem to nie wiem czy się dobrze zrozumieliśmy. 

Mamy jakiś odczyt np:  156 obr i jak potem jest zanik impulsów to robi mi się na wyświetlaczu 056.

Rozumiem...to użyj kodu który podałem na początku i do tego za każdym razem przed aktualizacją danych wypisz spacje...np jeśli twoja dana będzie z zakresu 3 cyfr to przed jej wyświetleniem wyświetl 3 spacje.... 

int kopia_predkosc;
int predkosc = analogRead(4); 

if (predkosc != kopia_prędkość) { 
  kopia_predkosc = prędkość; 
  //ustaw kursor 
  lcd.print("   ");
  //wyswietl zmienna prędkość 
}

 

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

(edytowany)

Koło obraca się wolno ale czujnik indukcyjny ma zliczać łby szpilek osadzonych w piaście. W tym przypadku na jeden obrót przypada 8 łbów = 8 impulsów. 

Edytowano przez Adonaktiv
Literowka
Link do komentarza
Share on other sites

38 minut temu, Adonaktiv napisał:

Mamy jakiś odczyt np:  156 obr i jak potem jest zanik impulsów to robi mi się na wyświetlaczu 056.

 

Dzisiejszy temat sponsoruje funkcja sprintf 🙂

char buforr[ileśtam];
sprintf(bufor,"%3d", ilosc_obrotow);
lcd.print(bufor);

 

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

22 minuty temu, Adonaktiv napisał:

Koło obraca się wolno ale czujnik indukcyjny ma zliczać łby szpilek osadzonych w piaście. W tym przypadku na jeden obrót przypada 8 łbów = 8 impulsów. 

A to już lepiej...😉  No to wywal tego while() i zastąp if'em jak podałem, to już nie będzie blokować

Link do komentarza
Share on other sites

7 minut temu, Adonaktiv napisał:

Czytałem twoje kody z tą funkcją nie raz ale to jeszcze nie mój poziom

Spróbuj zrozumieć jak to działa - to wcale nie takie skomplikowane, a niesamowicie ułatwia życie. Funkcja jest standardowa dla C/C++ a więc możesz sobie poczytać dowolny opis (np. linuxowy man ). A ja bym się bał podpinania do ciągnika czegoś, co zostało zaprogramowane przez gościa co nie zna podtawowych funkcji 🙂

Link do komentarza
Share on other sites

(edytowany)

Dzisiaj miałem chwilę aby posiedzieć przy komputerze i podłubać.

Czyszczenie ekranu ogarnąłem także kolejny punkt na liście celów odhaczony. Natomiast gorzej z pozbycia się tego while()

Próbowałem tak :

int getWOM() {

  unsigned long startTime1;
  int obrot;
  boolean wom = LOW;

    if (digitalRead(WOM) == LOW && wom == LOW) {
      wom = HIGH;
      obrot++;
    }
    if (digitalRead(WOM) == HIGH) {
      wom = LOW;
    }

    if (millis() - startTime1 >= 5000) {
    startTime1 = millis();
    rpm = 12 * obrot;
    

    }
    obrot = 0;
    return rpm;
}

I tak:

if (millis() - startTime1 >= 5000) {
    startTime1 = millis();
    rpm = 12 * obrot;
    obrot = 0;
    

    }

 

Wyjmowałem getWOM() z BoardComputer bezpośrednio do case 0 i  loop()  ale bez rezultatów. Jeszcze nie próbowałem oddzielnej funkcji do liczenia impulsów a oddzielnej do liczenia prędkości i resetowania zliczeni po danym czasie.

Testy

Edytowano przez Adonaktiv
Dodanie linka
Link do komentarza
Share on other sites

int getWOM()
{
    unsigned long startTime1;
    int obrot;
    boolean wom = LOW;

    if (digitalRead(WOM) == LOW && wom == LOW) {
        wom = HIGH;
        obrot++;
    }
    
    if (digitalRead(WOM) == HIGH) {
        wom = LOW;
    }

    if (millis() - startTime1 >= 5000) {
        startTime1 = millis();
        rpm = 12 * obrot;
    }
}

Warto dbać o porządek i czytelność. Każdy normalny edytor umożliwia automatyczne formatowanie. 

 

Link do komentarza
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!

Anonim
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...

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.