Skocz do zawartości
betepok

Chronograf kodowanie

Pomocna odpowiedź

Witam

Zbudowałem chronograf na podstawie LINK w zasadzie chronograf działa ale tylko przy małych prędkościach pocisku. Przy większych pokazuje głupoty lub nie wyłapuje pocisku. Zastanawiam się czy można poprawić program w taki sposób żeby szybsze pociski również były widziane. Upatruje problemu w samym kodzie ponieważ moje nieudolne próby modyfikacji kodu wskazały, że czujniki są w stanie przekazać informacje. Pocisk wystrzelony z wiatrówki, prędkość około 290m/s

Proszę o pomoc.

/*
Sketch to measure the time in uSeconds between two IR sensors being triggered
and sending the result to the serial port.
Use with the PC application to display results

Version 0.1
Phil Grant 25/04/13
*/

#include <Wire.h>
#include "Adafruit_LEDBackpack.h"
#include "Adafruit_GFX.h"
Adafruit_7segment matrix = Adafruit_7segment();

#define Trip_in_1 2  //set light Trigger 1 to pin D2  
#define Trip_in_2 3  //set light Trigger 2 to pin D3
#define WAIT_STATE 0
#define MONITOR_STATE 1
#define OUTPUT_STATE 2

unsigned long Trigger_1 = 0;
unsigned long Trigger_2 = 0;
volatile unsigned int current_state = WAIT_STATE;
char my_oldSREG;    //to hold status register while ints are disabled
unsigned long SensDist = 196850; //Distance between sensors in feet *1000000 60mm
unsigned long duration = 0; // time between triger 1 and 2
volatile boolean is_timeout = false;


void setup () {
 Serial.begin(57600);
 matrix.begin(0x70); //Setup 7 Seg Display
 pinMode(Trip_in_1, INPUT);
 pinMode(Trip_in_2, INPUT);
 digitalWrite(Trip_in_1, HIGH);  //turn on pullup resistor
 digitalWrite(Trip_in_2, HIGH);
 matrix.print(10000);
 matrix.writeDisplay();
 reset_variables();

}


void loop () {


 switch (current_state) {
 case WAIT_STATE:
   if(digitalRead(Trip_in_1)==LOW) {
     Trigger_1 = micros();
     current_state = MONITOR_STATE;
     // Timer1.setPeriod(my_timeout);
   }
   break;
 case MONITOR_STATE:
   while(digitalRead(Trip_in_2)==HIGH);  //loop until the Trigger goes LOW  && !is_timeout
   if(!is_timeout)
     Trigger_2 = micros();
   current_state = OUTPUT_STATE;
   break;
 case OUTPUT_STATE:
   //if (Trip2 > Trip1) {
   output_serial_info();
   reset_variables();
   current_state = WAIT_STATE;
   //}
   break;
 }
}

void output_serial_info() {


 // Serial.print("Duration\t");
 Serial.println((Trigger_2 - Trigger_1));
 //Serial.println(" uS");
   matrix.print(199475/(Trigger_2 - Trigger_1));
 matrix.writeDisplay();
}

void reset_variables() {
 Trigger_1 = 0;
 Trigger_2 = 0;
 is_timeout = false;
 //Timer1.stop();
}

Udostępnij ten post


Link to post
Share on other sites

A może najprościej rozsunąć czujniki i zmienić stałą do przeliczania µs na m/s? Wtedy procesor ma więcej czasu między aktywacją jednego i drugiego czujnika i nic nie musisz kombinować.

Jeżeli rozumiesz jak ten program działa (a w szczególności jak działają automaty FSM w C) to przecież bardzo prosto pętlę loop() zawierającą tylko jeden switch() zamienić na liniowo wykonywany program. Zauważ, że przejścia między stanami są tylko pojedyncze do stanu następnego - już prostszego FSM być nie może. To już coś poprawi. Potem zamiana funkcji systemowych micros() na bezpośrednie użycie timera i możesz mierzyć czasy od kilku µs, czyli przy odległości czujników np. 10cm daje to jakieś 20km/s.

Udostępnij ten post


Link to post
Share on other sites

Ja nie wiem jak to w arduino wygląda, bo dopiero się zaczynam bawić, ale ja bym to na dwóch przerwaniach zewnętrznych i timerze zrobił...

Udostępnij ten post


Link to post
Share on other sites
A może najprościej rozsunąć czujniki i zmienić stałą do przeliczania µs na m/s?

Czujniki oddaliłem. Wartość 100mm. Co daje 328083 i to na µs?

Żeby nie mącić zacząłem od początku. Program działa i nawet coś pokazuje (powtarzalnego) Mało estetycznie ale działa. Czy o to chodziło?

#include <Wire.h>


#define firstseans_1 10
#define secoundsens_2 11


unsigned long time1 = 0;
unsigned long time2 = 0;
float fps, elap;
int val;
int val2;



void setup() {
Serial.begin(9600);
pinMode (firstseans_1, INPUT);
pinMode (secoundsens_2, INPUT);
 digitalWrite(firstseans_1, HIGH);  
 digitalWrite(secoundsens_2, HIGH);
}

void loop() {

// Serial.println("Wal");
val = digitalRead(firstseans_1);
val2 = digitalRead(secoundsens_2);


if (digitalRead(firstseans_1) == LOW)
{
     time1 = micros();
     //Serial.println("Time1");
     //Serial.println(time1);

}
if (digitalRead(secoundsens_2) == LOW)
{
     time2 = micros();
     //Serial.println("Time2");
     //Serial.println(time2);

}


printserial();

//reset_variables(); 


}
void printserial(){
 elap = time1 - time2;
fps = 328083/elap;
Serial.println(fps ); 
}

void reset_variables() {
 time1 = 0;
 time2 = 0;
}

[ Dodano: 29-11-2015, 10:18 ]

dwóch przerwaniach zewnętrznych i timerze zrobił...

Czyli jak ?

Przepraszam za tak bezpośrednie pytanie ale nie jestem biegł ani w elektronice ani w programowaniu. Coś niecoś wiem i z tego coś niecoś staram się zrobić COŚ 🙂

Udostępnij ten post


Link to post
Share on other sites

Już lepiej, choć teraz program trochę bezsensownie przechodzi przez oba if-y i drukuje jakieś głupoty nawet jeśli nic w czujnikach się nie wydarzyło.

Spróbuj poprawić to tak, by:

1. Program najpierw czekał w pętli while na stan wysoki Czujnika 1 (to po to by nie trafił w tym miejscu na już uaktywniony Czujnik 1, bo wtedy pomiar będzie zły).

2. Czekał w pętli while na stan niski Czujnika 1.

3. Zapamiętywał czas.

4. Czekał w pętli while na stan niski Czujnika 2.

5. Zapamiętywał czas.

No i dalej to już wiadomo. Ważne, by między krokami 2-3-4-5 nie było żadnych niepotrzebnych opóźnień, nawet wstawek wypisujących wartości. Możesz je wypisać później, ale to jest "sekcja krytyczna" i od jej nieprzerwanego wykonania zależy powtarzalność wyników i oczywiście najkrótszy mierzony interwał czasu.

Od biedy możesz wstawić funkcję reset_variables() na początek pętli loop() i wypisywać wyniki tylko wtedy, gdy policzona różnica jest > 0.

Jeśli zastanawiasz się skąd procesor bierze wartości oddawane funkcją micros() to bardzo dobrze - to (po poprawkach) będzie największe źródło problemów Twojego pomiaru czasu. Ale o bezpośrednim sterowaniu timerem napiszę następnym razem 🙂

BTW: Dlaczego jeden czujnik nazywa się seans a drugi sens?

Udostępnij ten post


Link to post
Share on other sites

Po poprawkach wygląda to tak. Trochę bardziej uporządkowane. Jak zrobić żeby kolejne wyniki wyświetlały się jedne pod drugim po pomiarze. W tym momencie coś mierzy i cały czas drukuje wynik zapętla się. W sprawie nazwy zmiennej to literówka 🙂

#include <Wire.h>


#define firstseans_1 10
#define secoundsens_2 11



unsigned long time1 = 0;
unsigned long time2 = 0;
float fps, elap;
int val;
int val2;



void setup() {
Serial.begin(9600);
pinMode (firstseans_1, INPUT);
pinMode (secoundsens_2, INPUT);
 digitalWrite(firstseans_1, HIGH);  
 digitalWrite(secoundsens_2, HIGH);
}

void loop() {

//Serial.println("Wal...");
val = digitalRead(firstseans_1);
val2 = digitalRead(secoundsens_2);


while(digitalRead(firstseans_1) == LOW)
{
     time1 = micros();
     //Serial.println("Time1");
     //Serial.println(time1);

}

while(digitalRead(secoundsens_2) == LOW)
{
     time2 = micros();
     //Serial.println("Time2");
     //Serial.println(time2);
}

printserial();
}


void printserial(){
 elap = time1 - time2;
fps = 333333/elap;
Serial.println(fps ); 
}

void reset_variables() {
 time1 = 0;
 time2 = 0;
}

Udostępnij ten post


Link to post
Share on other sites

Jeszcze raz przeczytaj co opisałem w punktach i tak zrób. Wtedy wynik będziesz dostawał tylko wtedy, gdy coś przed czujnikami przeleci.

Dla ułatwienia: pętla while czekająca na stan niski wygląda tak:

while(digitalRead(firstseans_1)) {};

bo musi się kręcić w kółko gdy stan pinu jest wysoki, a dopiero po niej jest odczyt czasu - poza pętlą.

Udostępnij ten post


Link to post
Share on other sites

Chyba nie rokuje... 🙁

void loop() {

//Serial.println("Wal...");


while(digitalRead(firstsensor_1) == HIGH);  //czeka na stan wyskoki

while(digitalRead(firstsensor_1))                 //kręci sie caly czas
{
time1 = micros();                                     //po przekroczeniu zapamietuje wynik                 
    // Serial.println("Time1");
     //Serial.println(czujnik1);

};

while(digitalRead(secoundsensor_2))
{
 time2 = micros();    
    // Serial.println("Time2");
    // Serial.println(czujnik2);
};

printserial(); // przelicza i wywala wynik
}

[ Dodano: 29-11-2015, 15:36 ]

Wygląda na to, że tak to powinno być. Zgadza się?

#include <Wire.h>


#define firstsensor_1 10
#define secoundsensor_2 11



unsigned long time1;
unsigned long time2;
float fps, elap;
int czujnik1;
int czujnik2;



void setup() {
Serial.begin(9600);
pinMode (firstsensor_1, INPUT);
pinMode (secoundsensor_2, INPUT);
 digitalWrite(firstsensor_1, HIGH);  
 digitalWrite(secoundsensor_2, HIGH);
}

void loop() {

Serial.println("Wal...");
//czujnik1 = digitalRead(firstsensor_1);
//czujnik2 = digitalRead(secoundsensor_2);

while(digitalRead(firstsensor_1) == HIGH)

while(digitalRead(firstsensor_1))
{
time1 = micros();  
};

while(digitalRead(secoundsensor_2))
{
 time2 = micros();   
};

printserial();

}


void printserial(){
 elap = time2 - time1;
fps = 333333/elap;
Serial.println(fps ); 
}




Udostępnij ten post


Link to post
Share on other sites

OK, spróbuj tego:

while(digitalRead(firstsensor_1) == 0);  // kręci się dopóki na wejściu jest stan 0 -> czyli czeka na stan 1 - wtedy opuści pętlę i pójdzie dalej

while(digitalRead(firstsensor_1));  // kręci się dopóki na wejściu jest 1 -> czyli czeka na stan 0
time1 = micros();                                     // wykryliśmy początek impulsu czujnika 1 -> zapamiętujemy czas
while(digitalRead(secoundsensor_2));  // kręci się dopóki na wejściu jest 1 -> czyli czeka na stan 0
time2 = micros();                                     // wykryliśmy początek impulsu czujnika 2 -> zapamiętujemy czas

Reszta taka samo jak u Ciebie. To mierzy czas miedzy początkiem impulsu czujnika 1 a początkiem impulsu czujnika 2. Wydaje się proste.

Udostępnij ten post


Link to post
Share on other sites

Twój kod jest jakiś bardziej czytelny 🙂 Moje wypociny również zadziałały. Dzięki za pomoc.

Wspominałeś o micros() . Czy problem to dokładne rozmieszczenie czujników (równe 100mm) czy są jakieś haki zastosowanego obecnie rozwiązania?

Udostępnij ten post


Link to post
Share on other sites

Położenie czujników jest ważne w każdej metodzie, bo to Twoja baza pomiarowa. Na jej podstawie przeliczasz przecież czas na prędkość.

Metoda z funkcją micros() ma jedną podstawową wadę. Czas wyliczany jest przez ukrytą w kodzie wynikowym funkcję obsługi przerwania od Timera 0. A przerwania mają to do siebie, że w sposób nieoczywisty zabierają czas procesora. Tak więc jeśli zdarzy się tak, że przerwanie od tego timera wejdzie w czasie trwania pomiaru (między jednym while a drugim) to procesor zajmie się czymś innym i nie będzie mógł nadzorować stanu na wejściu drugiego czujnika. Gdy powróci do obsługi Twojego kodu mogą się zdarzyć dwie rzeczy: albo impuls czujnika 2 jeszcze trwa i wtedy pomiar się zakończy, ale będzie błędnie za duży, albo impuls już się skończył i wtedy program zwiśnie na oczekiwaniu impuls z tego czujnika, który już się nie pojawi. Oba przypadki są niefajne i nie masz nad nimi żadnej kontroli. Dopóki w trakcie takiego pomiaru masz włączone jakieś przerwania dopóty musisz się z tym liczyć, że od czasu do czasu wynik może być dziwny albo żaden. Dlatego dalszym ulepszeniem powinno być przejście z funkcji micros() na bezpośrednie użycie np. timera 1 bezpośrednio liczącym mikrosekundy przy globalnie zablokowanych przerwaniach.

Udostępnij ten post


Link to post
Share on other sites

Fakt coś w tym jest. Zajmę się tym.

Jeszcze jedna sprawa. W ostatnim kodzie miałem możliwości ustawienia wagi pocisku. Wywołane przez weight_settings();

na tym etapie nie za bardzo wiem gdzie to wcisnąć kod wykona się ale dopiero po tym jak sensor 1 zmienia stan na wysoki. To pewnie jakieś pytanie z podstaw programowania?

Udostępnij ten post


Link to post
Share on other sites

Pewnie tak.. 😖 Jeżeli to ma być jakaś stała do obliczeń energii pocisku, to umieść to gdziekolwiek przed jej użyciem, np. w setup().

Twój ostatni kod jest zły, ponieważ w każdej z pętli while wielokrotnie wywołujesz funkcje micros(). To bez sensu. Nie dość, że zabiera cenny czas to jeszcze pętle nie wykrywają tego co chcesz. Mam wrażenie, że zamiast zrozumieć zjawisko programujesz "objawowo" - dotąd kręcisz na czuja w kodzie aż zacznie oddawać jakieś wyniki. Pierwszy while zawiera drugi bo brakuje średnika i oczywiście nie robi tego co miał robić. Trochę ręce opadają..

Może spróbuj czegoś prostszego, nie wiem, poświęć tydzień na przejście kursu programowania Arduino albo przeczytaj książkę o C. Nie od razu Kraków zbudowano więc i tutaj może jest podobnie. Zostaw to urządzenie i wróć do niego gdy będziesz pewien, że rozumiesz co robisz. Tak to chyba żadnej satysfakcji nie ma, prawda? Urządzenie pomiarowe na którym masz polegać w dalszych pracach a dające w losowych przypadkach dziwne wyniki lepiej od razu wywalić na śmietnik (oczywiście oznaczony odpowiednim symbolem).

  • Lubię! 1

Udostępnij ten post


Link to post
Share on other sites

Masz trochę racji. Fakt programuje "objawowo". Muszę się mocno podszkolić. Dziękuję za pomoc i poświęcony czas. Sprawiłeś mi wiele radości.

Urządzenie działa i to w miarę powtarzalnie.

Wygląda TAK

Wyniki troszkę rozstrzelone bo nie zawsze trafiałem w dwa sensory

0.68 g - 10.5 gr

Shot number: 1

FPS 677.86

MPS 206.61

JOULE 14513.95

Shot number: 4

FPS 683.51

MPS 208.33

JOULE 14756.86

Shot number: 5

FPS 672.30

MPS 204.92

JOULE 14276.99

Shot number: 6

FPS 683.51

MPS 208.33

JOULE 14756.86

Shot number: 7

FPS 683.51

MPS 208.33

JOULE 14756.86

Shot number: 8

FPS 666.84

MPS 203.25

JOULE 14045.79

0,51 g - 7,9 gr

Shot number: 1

FPS 788.66

MPS 240.38

JOULE 14735.03

Shot number: 7

FPS 788.66

MPS 240.38

JOULE 14735.03

Shot number: 9

FPS 788.66

MPS 240.38

JOULE 14735.03

Shot number: 13

FPS 796.32

MPS 242.72

JOULE 15022.53

Shot number: 16

FPS 804.13

MPS 245.10

JOULE 15318.54

Shot number: 18

FPS 788.66

MPS 240.38

JOULE 14735.03

Udostępnij ten post


Link to post
Share on other sites

Gdybyś w domowych warunkach zbudował sprzęt nadający taką energię pociskom jak wypisujesz powyżej już byś siedział za kratami lub był martwy. Na szczęście to tylko błąd w obliczeniach. Do wzoru na energię kinetyczną powinieneś podstawiać prędkość w m/s i masę w kg. Wartości kilkunastu J jakie powinieneś uzyskać nie są małe i mogą zrobić krzywdę, ale przynajmniej nie rozwalają ścian nośnych budynków.

Używana przez program stała do przeliczeń czasu [us] na prędkość [m/s] powinna wynosić równo 100000. Jeżeli jest inaczej a wyniki masz dobre to albo czujniki są nierówne, albo liczysz czas od różnych zboczy albo odległość nie jest 10cm.

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