Hallo,
ich habe auch das Problem mit den Tastern gehabt. Die Lösung mit der Modifikation der Return-Zeile in Funktion PollSwitch finde ich zwar brauchbar, sie bleibt aber meiner Meinung nach eine Quick&Dirty-Lösung. Man kann den Multiplikator variieren (*62, *63, *64, was auch immer, sogar mit Nachkommastellen) um die Werte 0, 1, 2, 4, 8, 16 und 32 zu bekommen wenn EINEN Taster gedrückt wird. Ich glaube aber, dass es sehr schwer ist die 64 Werte aller möglichen Kombinationen korrekt zu bekommen! In der Praxis kommt natürlich sehr selten vor, dass mehrere Taster z.B. 1,2,3,4 bei Kollision gleichzeitig gedrückt werden. Es macht aber trotzdem Sinn: z.B. Wenn ich feststellen will ob der Asuro an der linken oder rechten Seite mit einem Obj. kollidiert (Taster 1 und 2) dann brauche ich 48 (also 110000) und nicht 47 oder 46.
Meine Lösung des Problems heißt "lineare Regression" oder "lineare Ausgleich". Im Prinzip versucht man die Messwerte durch eine Gerade zu beschreiben, wobei die Lage (Parameter) der Gerade die Lösung des Ausgleichsproblems ist. (Anm.: Die Formel in PollSwitch enthält bereits die (Daume-mal-Pi) Lösung des Ausgleichsproblems.)
Nun habe ich folgendes gemacht:
1) Als erstes versuche ich herauszufinden, welche Werte ich zurückbekomme (so genau wie möglich, ohne Info-verlust) wenn ich einen oder mehrere Taster drücke. Dazu habe ich folgendes Prg. verwendet:
#include "asuro.h"
/* function to read out switches */
unsigned int testSwitch (void)
{ unsigned int i;
DDRD |= SWITCHES; // Switches as Output
SWITCH_ON; // Output HIGH for measurement
ADMUX = (1 << REFS0) | SWITCH; // AVCC reference with external capacitor
Sleep(10);
ADCSRA |= (1 << ADSC); // Start conversion
while (!(ADCSRA & (1 << ADIF)));// wait for conversion complete
ADCSRA |= (1 << ADIF); // clear ADCIF
i = ADCL + (ADCH << 8);
SWITCH_OFF;
Sleep(5);
return (int)(1023000L/(long)i);
}
int main(void)
{
Init();
StatusLED(OFF);
SerWrite("\n\rtest switch:\n",15);
StatusLED(GREEN);
while(1) {
int j;
long sum = 0, sw=0;
SerWrite("\n\r",2);
while (!PollSwitch());
Msleep(100);
for (j = 0; j < 100; j++)
sum += testSwitch();
int sw1,sw2;
do {
sw1 = PollSwitch();
sw2 = PollSwitch();
} while (sw1 != sw2);
PrintInt((int)(sum/100.0)+0.5);
Msleep(200);
SerWrite(" ",2);
PrintInt(sw1);
}
return 0;
}
Die Messwerte (1023/y) werden sozusagen direkt aufsummiert und Durchschnitt gebildet.
2) Anhand der Werte und die Formel in PollSwitch lässt sich vermuten, dass 1/y linear ist. Die Formel ist auch nichts anders als lineare Transformation. Wegen der herstellungsbedingten Ungenauigkeit der Widerstände liegen die Messwerte 1023/y nicht auf einer Gerade.
3) Als nächste habe ich Matlab angeworfen und die Ausgleichgerade berechnet:
Z = 1./y;
X = [ones(64,1) (0:63)'];
p = X\Z; % Lsg des Glg-Systems -> Koeff. der Gerade p
Z_out = (Z-p(1))/p(2);
4) Für denjenigen, der kein Matlab hat, habe ich was vorgerechnet.
Die Werte 1/y aus 1) im folgenden Prg dem y zuweisen.
#include "asuro.h"
int main(void)
{
// y wird durch indiv. Messwerte ersetzt
int y[] = {1000, 1015, 1031, 1047, 1062, 1079, 1095, 1111, 1125, 1142,
1157, 1173, 1190, 1206, 1222, 1238, 1258, 1274, 1290, 1307,
1322, 1339, 1355, 1369, 1384, 1401, 1417, 1433, 1449, 1466,
1480, 1498, 1525, 1541, 1557, 1574, 1589, 1606, 1621, 1637,
1653, 1669, 1685, 1699, 1716, 1734, 1749, 1764, 1785, 1801,
1817, 1833, 1850, 1867, 1881, 1898, 1912, 1930, 1945, 1960,
1975, 1994, 2010, 2026},
A[2][64] = {{
6106, 5962, 5817, 5673, 5529, 5385, 5240, 5096, 4952, 4808,
4663, 4519, 4375, 4231, 4087, 3942, 3798, 3654, 3510, 3365,
3221, 3077, 2933, 2788, 2644, 2500, 2356, 2212, 2067, 1923,
1779, 1635, 1490, 1346, 1202, 1058, 913, 769, 625, 481,
337, 192, 48, -96, -240, -385, -529, -673, -817, -962,
-1106, -1250, -1394, -1538, -1683, -1827, -1971, -2115, -2260, -2404,
-2548, -2692, -2837, -2981},
{
-144, -140, -135, -130, -126, -121, -117, -112, -108, -103,
-98, -94, -89, -85, -80, -76, -71, -66, -62, -57,
-53, -48, -43, -39, -34, -30, -25, -21, -16, -11,
-7, -2, 2, 7, 11, 16, 21, 25, 30, 34,
39, 43, 48, 53, 57, 62, 66, 71, 76, 80,
85, 89, 94, 98, 103, 108, 112, 117, 121, 126,
130, 135, 140, 144}};
int i;
float p1,p2,fkt=1.e5;
p1 = p2 = 0;
Init();
SerWrite("\n\rlin.Regression:\n\r",19);
for (i = 0; i < 64; i++) {
p1 += (float)A[0][i]*(float)y[i];
p2 += (float)A[1][i]*(float)y[i];
}
p1 /= fkt;
SerWrite("bias: 0.",8);
Msleep(100);
PrintInt(p1);
SerWrite("\n\r",2);
p2 = 1000*fkt/p2;
SerWrite("slope: ",7);
Msleep(100);
PrintInt(p2);
SerWrite(".",2);
PrintInt((int)((p2-(int)p2)*10.0+0.5));
SerWrite("\n\r",2);
while (1);
return 0;
}
Das Prg spuckt zwei Werte aus: bias b (bei mir 0.995) und slope s (die Steigung der Gerade, bei mir 61.0).
5) Zum Schluß wird die Return-Zeile noch korrigiert mit:
return ((unsigned char) ((( 1023.0/(float)i - 0.995)) * 61.0 + 0.5));
Mit diesem Feintuning habe ich alle 64 Werte richtig. Probiert habe ich mit und ohne Motor eingeschalten. Hier ist noch das Testprg. Es gibt die Messwerte und die transf. Werte 1 bis 63 aus.
#include "asuro.h"
/* function to read out switches */
unsigned int testSwitch (void)
{ unsigned int i;
DDRD |= SWITCHES; // Switches as Output
SWITCH_ON; // Output HIGH for measurement
ADMUX = (1 << REFS0) | SWITCH; // AVCC reference with external capacitor
Sleep(10);
ADCSRA |= (1 << ADSC); // Start conversion
while (!(ADCSRA & (1 << ADIF)));// wait for conversion complete
ADCSRA |= (1 << ADIF); // clear ADCIF
i = ADCL + (ADCH << 8);
SWITCH_OFF;
Sleep(5);
return (int)(1023000L/(long)i);
}
int main(void)
{
Init();
StatusLED(OFF);
SerWrite("\n\rtest switch:\n",15);
StatusLED(GREEN);
while(1) {
int j;
long sum = 0;
SerWrite("\n\r",2);
MotorDir(FWD,FWD);
MotorSpeed(150,150);
while (!PollSwitch());
Msleep(100);
for (j = 0; j < 100; j++)
sum += testSwitch();
int sw1,sw2;
do {
sw1 = PollSwitch();
sw2 = PollSwitch();
} while (sw1 != sw2);
PrintInt((int)(sum/100.0)+0.5);
SerWrite(" ",2);
Msleep(200);
PrintInt(sw1);
if (sw1 & 0x7)
MotorDir(RWD,RWD);
else
MotorDir(FWD,FWD);
MotorSpeed(150,150);
Msleep(500);
}
return 0;
}
Ich hoffe, dass diese codes hilfreich sind. Falls jemand einen Fehler entdeckt, bitte melden. Wenn jemand sich interessiert, kann ich auch kurz erläutern, wie das lin. Ausgleichsproblem analytisch gelöst wird (auf die Frage, wieso sieht die 2x64-Matrix A so aus).
Felix
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.