Italian Problema con contachilometri

D

Deleted member 103

Guest
Ciao ragazzi(e),

avrei bisogno di un piccolo aiuto.

Si tratta di un contachilometri che non vuole fare quello che voglio io. :(
Il codice è una frazione di un'altra App e serve solo per simulare gli impulsi che riceve la classe "clsSpeedmeter" da un dispositivo bluetooth. Ogni impulso corrisponde a un giro di routa.

Come si può vedere dal video, la visuale del contachilometri non è tanto stabile, varia da 54 a 57 km/h.
Penso che questa instabilità sia dovuta al mio non perfetto codice.

C'è qualcuno che saprebbe risolvere questo "piccolo" problema? :)

Grazie in anticipo
Filippo
 

Attachments

  • fg-speedmeter.zip
    8.6 KB · Views: 227
  • video_speedmeter.zip
    179.3 KB · Views: 226
D

Deleted member 103

Guest
Qual'è esattamente il problema?


Dovrebbe raggiungere anche valori + bassi e/o + alti?
No Luca, non è questo il problema.
Se imposto 50 km/h dovrebbe visualizzare sempre 50 km/h o almeno sempre lo stesso valore, senza questi sbalzi.
 
D

Deleted member 103

Guest
Cerco di speigare il flusso. :(

Il Timer "Sendtimer" manda ogni x-millisecondi un impulso alla classe "clsSpeedmeter".
Un impulso corrisponde, nel mio caso, a 1944mm(che sono la circonferenza di una routa).
In base alla velocità del Timer "Sendtimer", che si puo cambiare per mezzo dello "SeekBar1", e la distanza percorsa, vorrei visualizzare la velocità attuale.
Fino qua è tutto bene.
Il problema è che la velocità visualizzata fa troppi sbalzi di vallore.
Ora non sò se è un problema dei Timer o nel calcolo della velocità attuale. :(
 

LucaMs

Expert
Licensed User
Longtime User
Provo a scrivere come mi sembra funzioni attualmente il programma (così ci ragiono sopra, sperando che qualcun altro trovi la soluzione :p).

Hai una SeekBar con la quale imposti la velocità: valori tra 0 e 200 (km/h).
In base al valore di questa "velocità", calcoli l'intervallo del timer SendTimer, che quindi avrà valori 0 (per velocità 0), 7000 (per velocità 1),... 35 (per velocità 200).
L'evento di SendTimer verrà quindi scatenato con maggiore frequenza in base alla velocità selezionata.
L'evento chiama il metodo NewData della classe clsSpeed. In questo metodo viene impostato un tempo iniziale StartTime (al primo ricevimento di NewData), se è il secondo "dato" ricevuto, viene calcolato il tempo trascorso (che sarà tra il secondo tick ed il primo). Poi viene calcolato:
B4X:
tmpSpeed = Abrollumfang / time * 3600
ovvero la circonferenza della ruota diviso il tempo trascorso, moltiplicato per 3600 suppongo per calcolare la velocità oraria.

Ma questo sarebbe giusto se i tick di SendTimer corrispondessero al giro completo della ruota (e non mi sembra così) o sbaglio?

Se, come penso, il SendTimer deve simulare un sensore sulla ruota per contare i giri della ruota, Abrollumfang deve intervenire nel calcolo nel Main, per far sì che ogni SendTimer_Tick avvenga ad ogni giro di ruota completato.

Oppure...

non c'ho capito un tubo :p
 

LucaMs

Expert
Licensed User
Longtime User
Se effettivamente il SendTimer deve scatenare un evento ad ogni giro di ruota completato, l'istruzione dovrebbe essere (se non ho sbagliato!):

Sendtimer.Interval = 3600 / SeekBar1.Value / Abrollumfang

(ovviamente impostando una variabile Abrollumfang = 1.944 nel Main).

Poi, però, il calcolo nella NewData non mi è chiarissimo :D
 
D

Deleted member 103

Guest
Provo a scrivere come mi sembra funzioni attualmente il programma (così ci ragiono sopra, sperando che qualcun altro trovi la soluzione :p).

Hai una SeekBar con la quale imposti la velocità: valori tra 0 e 200 (km/h).
In base al valore di questa "velocità", calcoli l'intervallo del timer SendTimer, che quindi avrà valori 0 (per velocità 0), 7000 (per velocità 1),... 35 (per velocità 200).
L'evento di SendTimer verrà quindi scatenato con maggiore frequenza in base alla velocità selezionata.
L'evento chiama il metodo NewData della classe clsSpeed. In questo metodo viene impostato un tempo iniziale StartTime (al primo ricevimento di NewData), se è il secondo "dato" ricevuto, viene calcolato il tempo trascorso (che sarà tra il secondo tick ed il primo). Poi viene calcolato:
B4X:
tmpSpeed = Abrollumfang / time * 3600
ovvero la circonferenza della ruota diviso il tempo trascorso, moltiplicato per 3600 suppongo per calcolare la velocità oraria.

Ma questo sarebbe giusto se i tick di SendTimer corrispondessero al giro completo della ruota (e non mi sembra così) o sbaglio?

Se, come penso, il SendTimer deve simulare un sensore sulla ruota per contare i giri della ruota, Abrollumfang deve intervenire nel calcolo nel Main, per far sì che ogni SendTimer_Tick avvenga ad ogni giro di ruota completato.

Oppure...

non c'ho capito un tubo :p
Qui lo hai spiegato e capito perfettamente, bravo! Meglio non potevo neanche io spiegarlo. :)
Nelle altre 2 risposte ti sei però perso. :(

Il Seekbar mi serve solo per simulare il sensore che ho nella ruota, e va bene così. Anche il Timer "Sendtimer" è giusto.
La sola cosa che non va bene, penso io, è la classe "clsSpeedmeter". Qui dovrei trovare una routine, per calcolare l'attuale velocità, più stabile cioè senza tutti quei sbalzi come si vedono nel video.

Se, come penso, il SendTimer deve simulare un sensore sulla ruota per contare i giri della ruota, Abrollumfang deve intervenire nel calcolo nel Main, per far sì che ogni SendTimer_Tick avvenga ad ogni giro di ruota completato.
Infatti il tempo del "SendTimer" serve per simulare il giro completto.
 

LucaMs

Expert
Licensed User
Longtime User
Infatti il tempo del "SendTimer" serve per simulare il giro completto.
Allora è sbagliato come imposti l'intervallo del SendTimer, secondo me. Dovrebbe essere come ho scritto prima:
Sendtimer.Interval = 3600 / SeekBar1.Value / Abrollumfang
Esempio:
SeekBar1.Value = 100 (100 km/h)
Abrollumfang (circonferenza ruota) supponiamo 2m
3600 / 100 / 2 = 18

ogni 18 millesimi di secondo viene completato un giro di ruota; questo dovrebbe essere il valore di SendTimer.Interval.

Dopo non ho indagato bene la faccenda degli StepCounter, che servono a te per qualche altro scopo.
 

LucaMs

Expert
Licensed User
Longtime User
No, scusa, è sbagliato; è:

SendTimer.Interval = 3600 * Abrollumfang / SeekBar1.Value

Tu, in effetti, hai messo:

Sendtimer.Interval = 7000 / SeekBar1.Value

che è quasi esatto: 3600 * Abrollumfang cioè 3600 * 1.944 = 6998.4
 
D

Deleted member 103

Guest
Esempio:
SeekBar1.Value = 100 (100 km/h)
Abrollumfang (circonferenza ruota) supponiamo 2m
3600 / 100 / 2 = 18
Anche se questo fosse giusto, rimane sempre il fatto degli "sbalzi".

Il "StepCounter" serve a non dover calcolare la velocità ad ogni giro di routa, perchè sarebbe meno preciso.
Con questa variabile calcolo la velocita in base alla velocità. Es. se vado a 25 km/h allora ogni 4 giri, se vado a 50km/h allora ogni 7 giri, e così via...
 

LucaMs

Expert
Licensed User
Longtime User
Penso che l'errore sia in:
TempDistance = counter * Abrollumfang

che dovrebbe essere
TempDistance = (counter - 1) * Abrollumfang

Inoltre: ho impostato tutte le variabili a Double, quelle Long sono sbagliate.
Infine, i timer nel Main non sono perfetti al micro secondo ;)
 

LucaMs

Expert
Licensed User
Longtime User
Che fatica :D

Il Long è giusto, sono io che ho fuso.

Il punto è che tu calcoli la velocità al secondo tick del SendTimer in questo modo:
B4X:
            Else If counter = 2 Then
                time = DateTime.Now - starttime
                tmpSpeed = Abrollumfang / time * 3600
Se aggiungi un log:
B4X:
Log("initial speed =" & tmpSpeed)
Io metto a 100 SeekBar1.Value nella Resume (quindi fin da subito)
eppure il log non riporta 100 esatti, ma un decimale 101.42xxxx
Già questo è un valore errato; poi tu lo moltiplichi per non calcolare la velocità sempre e quindi i valori sono "traballanti".

Suppongo che il problema sia l'evento di SendTimer che non è preciso al millesimo (per cui il primo calcolo della velocità non è mai uguale a quella impostata tramite la SeekBar1).
 
D

Deleted member 103

Guest
Suppongo che il problema sia l'evento di SendTimer che non è preciso al millesimo (per cui il primo calcolo della velocità non è mai uguale a quella impostata tramite la SeekBar1).
Quindi se si esclude che l'errore non è nella classe, può essere solo nel SendTimer e questo risolverebbe il mio problema. :)
 
D

Deleted member 103

Guest
Mi sembra d'aver trovato una migliore soluzione al mio problema. :)
Questa è la nuova classe "clsSpeedmeter.bas":
B4X:
'Class module
Sub Class_Globals
    'Globale Variablen notwendig für die Verbindung
    Public IsBtConnected As Boolean
    'Variablen für Speed-Berechnung
    Private speed As Float
    Private starttime As Long
    Private timerSpeed As Timer
    Private Abrollumfang As Float
    Private time As Long
    Private rpm_array(5) As Float
End Sub

'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize
    IsBtConnected        = False
    speed                = 0
    Abrollumfang        = 1.944 'mm

    timerSpeed.Initialize("timerSpeed", 200)
    timerSpeed.Enabled = True
End Sub

Public Sub NewData (KeyCode As String)
       
    Select KeyCode
        Case "+"

            time = DateTime.Now - starttime
           
            '5 Sample Moving Average To Smooth Out The Data
            rpm_array(0) = rpm_array(1)
            rpm_array(1) = rpm_array(2)
            rpm_array(2) = rpm_array(3)
            rpm_array(3) = rpm_array(4)
            rpm_array(4) = Abrollumfang / time * 3600
            'Last 5 Average RPM Counts Eqauls....
            speed = (rpm_array(0) + rpm_array(1) + rpm_array(2) + rpm_array(3) + rpm_array(4)) / 5
               
            starttime = DateTime.Now
           
    End Select
End Sub

Public Sub getBTSpeed As Float
    Return speed
End Sub

Sub timerSpeed_Tick
    'Tacho auf null setzten nach 1000 millisec. stillstand.
    If DateTime.Now - starttime > time * 2 Then
        Log("speed resetet bei=" & (DateTime.Now - starttime))
        speed = 0
    End If   
End Sub
 
Top