Ich habe in Matlab-Simulink einen Zustandregler mit Beobachter für ein inverses Pendel ausgelegt und diskretisiert. http://www.library.cmu.edu/ctms/ctms/state/obs.gif Ich bin dabei analog zu: http://www.library.cmu.edu/ctms/ctms/examples/pend/diginvss.htm vorgegangen. Nun möchte ich diesen Zustandsregler auf einem Mikrocontroller (Arduino Mega) implementieren. Folgende Gleichungen habe ich aufgestellt: x[n + 1] = Ax[n] + Bu[n] wobei u[n] = - Kx[n] (negativ rückgekoppelt) x[n + 1] = Ax[n] - BKx[n] = (A-BK)x[n] Mit dem Beobachter sieht das ganze so aus: x^[n + 1] = (A-BK)x^[n] - L(y^-y) x^ = predicted state, y^ = predicted output, y= measured outputs Implementiert habe ich das ganze volgendermassen: . . . . //matrix A-B*K const double matr_A_BK[4][4] = { 1.0013, 0.0112, -0.0061, -0.0020, 0.2633, 1.2461, -1.2260, -0.4024, 0.0012, 0.0012, 0.9947, 0.0081, 0.2489, 0.2326, -1.0661, 0.6201 }; const double matr_L[2][4] = { 2.6319, -0.0108, 173.1476, -1.3975, -0.0086, 2.6289, -1.1521, 172.8517 }; const double matr_K[4] = { -65.9759, -61.7565, 314.0219, 100.8610 }; double state[4] = { 0, 0, 0, 0}; //state vector double nstate[4] = { 0, 0, 0, 0}; //temporarly stores new state . . . . p[0] = state[0]; //two predicted states (x^ and theta^) p[1] = state[2]; read_current_distance_m1(); s[1] = (distanceM1-initDistanceM1)/6573.75; //two sensors (x and theta) s[2] = (analogRead(10)-513.0); for(int i = 0; i < 4; i++) { for(int j = 0; j < 4; j++) { // (A-BK)*state nstate[i] = nstate[i] + matr_A_BK[i][j]*state[j]; } for(int j = 0; j < 2; j++) { //-L*pred + L*measures nstate[i] = nstate[i] + matr_L[i][j]*( s[j] - p[j] ); } } //update states for(int i = 0; i<4; i++) { state[i] = nstate[i]; nstate[i] = 0; //init for following cycle } . . . . Leider muss aber ein Fehler im Code vorhanden sein, die Variable nstate[i] ist nämlich immer 0.00. Könnt Ihr mir sagen, ob dieser Ansatz der Implementierung überhaupt richtig ist?
Kann mir niemand einen Rat dazu geben? Ich wäre schon um einen Literaturverweis für die Implementierung eines Zustandsreglers dankbar...
dein code sieht aber nicht so aus, oder...? poste mal alles, und benutze die code- einbettungsfunktion des forums.. oder wenns zuviel wird, häng die datei an..
Der Code wurde für einen Arduino Mega geschrieben und besteht aus zwei Dateien: StateSpaceControl.ino: Beinhaltet den Regel Algorithmus RoboClaw.ino: Beinhaltet die Kommunikation zum Motor Controller. StateSpaceControl.ino:
1 | #define SERIAL_BAUD 57600
|
2 | #define INPUT_COUNT 5 //number of analog inputs
|
3 | #define VDD 5000.0f //Analog reference voltage in mV
|
4 | #define PI 3.14159265358979f
|
5 | |
6 | //DIGITAL OUTPUT
|
7 | int ledGREENpin = 2; |
8 | int ledREDpin = 3; |
9 | int oscilloscopePin = 8; //oscilloscope pin to work out the program loop time |
10 | boolean oscilloscopeState = false; |
11 | |
12 | //Analog Input
|
13 | float poti8 = 0; |
14 | float poti9 = 0; |
15 | |
16 | |
17 | //Global variables Motor Controller-----------------------------------------------------------------------------------------------
|
18 | float level = 0; |
19 | int speedMotor1; |
20 | long distanceM1=0; |
21 | long initDistanceM1=0; |
22 | |
23 | //matrix A-B*K
|
24 | const double matr_A_BK[4][4] = { |
25 | 1.0013, 0.0112, -0.0061, -0.0020, |
26 | 0.2633, 1.2461, -1.2260, -0.4024, |
27 | 0.0012, 0.0012, 0.9947, 0.0081, |
28 | 0.2489, 0.2326, -1.0661, 0.6201 }; |
29 | |
30 | const double matr_L[2][4] = { |
31 | 2.6319, -0.0108, |
32 | 173.1476, -1.3975, |
33 | -0.0086, 2.6289, |
34 | -1.1521, 172.8517 }; |
35 | |
36 | const double matr_K[4] = { |
37 | -65.9759, -61.7565, 314.0219, 100.8610 }; |
38 | |
39 | double state[4] = { |
40 | 0, 0, 0, 0}; //state vector |
41 | |
42 | double nstate[4] = { |
43 | 0, 0, 0, 0}; //temporarly stores new state |
44 | |
45 | |
46 | void setup() { |
47 | Serial.begin(SERIAL_BAUD); |
48 | setupRoboClaw(); |
49 | |
50 | //digital outputs
|
51 | pinMode(ledREDpin, OUTPUT); |
52 | pinMode(ledGREENpin, OUTPUT); |
53 | pinMode(oscilloscopePin, OUTPUT); |
54 | |
55 | digitalWrite(ledREDpin, HIGH); |
56 | digitalWrite(ledGREENpin, LOW); |
57 | Serial.println("start"); |
58 | read_current_distance_m1(); |
59 | initDistanceM1=distanceM1; |
60 | }
|
61 | |
62 | void loop() { |
63 | |
64 | double p[2] = { |
65 | 0,0 }; //two predicted state |
66 | double s[2] = { |
67 | 0,0 }; //two outputs |
68 | double force = 0; //force that must be applied to motor |
69 | long now = millis(); |
70 | long last = millis(); |
71 | |
72 | |
73 | while(1) { //-------------CYCLE |
74 | digitalWrite(ledREDpin, LOW); |
75 | digitalWrite(ledGREENpin, HIGH); |
76 | now = millis(); |
77 | |
78 | while(last == now) { //wait until 1 microsecond elapses |
79 | // sample time = 1 ms
|
80 | now = millis(); |
81 | }
|
82 | last = now; |
83 | |
84 | // -L*pred + L*measures
|
85 | p[0] = state[0]; //two predicted states (x^ and theta^) |
86 | p[1] = state[2]; |
87 | read_current_distance_m1(); |
88 | s[0] = (distanceM1-initDistanceM1)/6573.75; //two sensors (x and theta) |
89 | s[1] = (analogRead(10)-511.0)*0.00405890523719604651162790697674; |
90 | |
91 | |
92 | for(int i = 0; i < 4; i++) { |
93 | for(int j = 0; j < 4; j++) { // _________(A-BK)*state |
94 | nstate[i] = nstate[i] + matr_A_BK[i][j]*state[j]; |
95 | }
|
96 | for(int j = 0; j < 2; j++) { //-L*pred + L*measures |
97 | nstate[i] = nstate[i] + matr_L[i][j]*( s[j] - p[j] ); |
98 | }
|
99 | Serial.print(" nstate["); |
100 | Serial.print(i); |
101 | Serial.print("]= "); |
102 | printDouble(nstate[i],10); |
103 | }
|
104 | Serial.println(" end for"); |
105 | |
106 | |
107 | //update states
|
108 | for(int i = 0; i<4; i++) { |
109 | state[i] = nstate[i]; |
110 | nstate[i] = 0; //init for following cycle |
111 | }
|
112 | |
113 | |
114 | // controller action
|
115 | force = 0; |
116 | for(int i = 0; i < 4; i++) { //controller action |
117 | force = force + (state[i]*matr_K[i]); |
118 | }
|
119 | level = force * 6666.6; |
120 | set_motor(); |
121 | |
122 | }//end of while(1) |
123 | }
|
124 | |
125 | void printDouble( double val, byte precision){ |
126 | // prints val with number of decimal places determine by precision
|
127 | // precision is a number from 0 to 6 indicating the desired decimial places
|
128 | // example: printDouble( 3.1415, 2); // prints 3.14 (two decimal places)
|
129 | |
130 | Serial.print (int(val)); //prints the int part |
131 | if( precision > 0) { |
132 | Serial.print("."); // print the decimal point |
133 | unsigned long frac; |
134 | unsigned long mult = 1; |
135 | byte padding = precision -1; |
136 | while(precision--) |
137 | mult *=10; |
138 | |
139 | if(val >= 0) |
140 | frac = (val - int(val)) * mult; |
141 | else
|
142 | frac = (int(val)- val ) * mult; |
143 | unsigned long frac1 = frac; |
144 | while( frac1 /= 10 ) |
145 | padding--; |
146 | while( padding--) |
147 | Serial.print("0"); |
148 | Serial.print(frac,DEC) ; |
149 | }
|
150 | }
|
RoboClaw.ino:
1 | #define address 128
|
2 | #define ROBOCLAW_BAUD 38400
|
3 | |
4 | signed char Motor1percent = 0; |
5 | signed char Motor2percent = 0; |
6 | int incomingByte= 0; |
7 | |
8 | void setupRoboClaw() |
9 | {
|
10 | Serial1.begin(ROBOCLAW_BAUD); |
11 | delay(100); |
12 | set_min_main_voltage_value(15); //9V formula: (voltage-6)*5 |
13 | set_max_main_voltage_value(82); //16V formula: voltage*5.25 |
14 | set_min_logic_voltage_value(15); //9V formula: (voltage-6)*5 |
15 | set_max_logic_voltage_value(82); //16V formula: voltage*5.25 |
16 | delay(100); |
17 | set_speed_m1_m2(0,0); |
18 | |
19 | }
|
20 | |
21 | /*
|
22 | ** 2 - Set Minimum Main Voltage
|
23 | ** Sets main battery (B- / B+) minimum voltage level. If the battery voltages drops below the set
|
24 | ** voltage level Robo Claw will shut down. The value is cleared at start up and must set after each
|
25 | ** power up. The voltage is set in .2 volt increments. A value of 0 sets the minimum value allowed which
|
26 | ** is 6V. The valid data range is 0 - 120 (6V - 30V). The formula for calculating the voltage is: (Desired
|
27 | ** Volts - 6) x 5 = Value. Examples of valid values are 6V = 0, 8V = 10 and 11V = 25. Example with
|
28 | ** Robo Claw address set to 128:
|
29 | **
|
30 | ** Serout P15, i19200, [128, 2, 25, (165 & 0X7F)]
|
31 | */
|
32 | |
33 | void set_min_main_voltage_value(byte min_main_battery_voltage) |
34 | {
|
35 | byte serial_data[4]; |
36 | serial_data[0]=address; |
37 | serial_data[1]=2; |
38 | serial_data[2]=min_main_battery_voltage; |
39 | serial_data[3]=(serial_data[0] + serial_data[1] + serial_data[2]) & 0x7F; |
40 | |
41 | Serial1.write(serial_data, sizeof(serial_data)); |
42 | }
|
43 | |
44 | /*
|
45 | ** 3 - Set Maximum Main Voltage
|
46 | ** Sets main battery (B- / B+) maximum voltage level. The valid data range is 0 - 154 (0V - 30V). If
|
47 | ** you are using a battery of any type you can ignore this setting. During regenerative breaking a back
|
48 | ** voltage is applied to charge the battery. When using an ATX type power supply if it senses anything
|
49 | ** over 16V it will shut down. By setting the maximum voltage level, Robo Claw before exceeding it will
|
50 | ** go into hard breaking mode until the voltage drops below the maximum value set. The formula for
|
51 | ** calculating the voltage is: Desired Volts x 5.12 = Value. Examples of valid values are 12V = 62, 16V
|
52 | ** = 82 and 24V = 123. Example with Robo Claw address set to 128:
|
53 | **
|
54 | ** Serout P15, i19200, [128, 3, 82, (213 & 0X7F)]
|
55 | */
|
56 | |
57 | void set_max_main_voltage_value(byte max_main_battery_voltage) |
58 | {
|
59 | |
60 | byte serial_data[4]; |
61 | serial_data[0]=address; |
62 | serial_data[1]=3; |
63 | serial_data[2]=max_main_battery_voltage; |
64 | serial_data[3]=(serial_data[0] + serial_data[1] + serial_data[2]) & 0x7F; |
65 | |
66 | Serial1.write(serial_data, sizeof(serial_data)); |
67 | }
|
68 | |
69 | |
70 | void set_min_logic_voltage_value(byte min_logic_battery_voltage) |
71 | {
|
72 | byte serial_data[4]; |
73 | serial_data[0]=address; |
74 | serial_data[1]=26; |
75 | serial_data[2]=min_logic_battery_voltage; |
76 | serial_data[3]=(serial_data[0] + serial_data[1] + serial_data[2]) & 0x7F; |
77 | |
78 | Serial1.write(serial_data, sizeof(serial_data)); |
79 | }
|
80 | |
81 | void set_max_logic_voltage_value(byte max_logic_battery_voltage) |
82 | {
|
83 | byte serial_data[4]; |
84 | serial_data[0]=address; |
85 | serial_data[1]=27; |
86 | serial_data[2]=max_logic_battery_voltage; |
87 | serial_data[3]=(serial_data[0] + serial_data[1] + serial_data[2]) & 0x7F; |
88 | |
89 | Serial1.write(serial_data, sizeof(serial_data)); |
90 | }
|
91 | |
92 | void set_speed_m1_m2(long speedM1, long speedM2) { |
93 | byte ab[11]; |
94 | ab[0] = address; |
95 | ab[1] = 37; |
96 | ab[2] = (speedM1 >> 24) & 0xff; |
97 | ab[3] = (speedM1 >> 16) & 0xff; |
98 | ab[4] = (speedM1 >> 8) & 0xff; |
99 | ab[5] = (speedM1 >> 0) & 0xff; |
100 | ab[6] = (speedM2 >> 24) & 0xff; |
101 | ab[7] = (speedM2 >> 16) & 0xff; |
102 | ab[8] = (speedM2 >> 8) & 0xff; |
103 | ab[9] = (speedM2 >> 0) & 0xff; |
104 | ab[10] = (ab[0]+ab[1]+ab[2]+ab[3]+ab[4]+ab[5]+ab[6]+ab[7]+ab[8]+ab[9]) & 0x7f; |
105 | Serial1.write(ab, sizeof(ab)); |
106 | }
|
107 | |
108 | void read_current_distance_m1() |
109 | {
|
110 | byte ab[2]; |
111 | ab[0] = address; |
112 | ab[1] = 16; |
113 | Serial1.write(ab, sizeof(ab)); |
114 | delay(10); |
115 | |
116 | byte distanceM1_byte[4]; |
117 | // send data only when you receive data:
|
118 | int i=0; |
119 | while (Serial1.available() > 0) { |
120 | if (i<4){ |
121 | distanceM1_byte[i] = Serial1.read(); |
122 | }
|
123 | i++; |
124 | }
|
125 | distanceM1 = ((long )distanceM1_byte[0]) << 24; |
126 | distanceM1 |= ((long )distanceM1_byte[1]) << 16; |
127 | distanceM1 |= ((long )distanceM1_byte[2]) << 8; |
128 | distanceM1 |= distanceM1_byte[3]; |
129 | }
|
Der debug output sieht wie folgt aus:
1 | start
|
2 | nstate[0]= 0.0003028782 nstate[1]= 0.0737256000 nstate[2]= -12.0398380160 nstate[3]= 0.0000000000 end for |
3 | nstate[0]= 0.0072283688 nstate[1]= 48.0991425344 nstate[2]= -787.0603735872 nstate[3]= 13.0303843360 end for |
4 | nstate[0]= -3.0112114600 nstate[1]= 3091.0715704576 nstate[2]= 16104.0000000000 nstate[3]= 858.1392766592 end for |
5 | nstate[0]= -194.0648187712 nstate[1]= -2546.0000000000 nstate[2]= -21931.0000000000 nstate[3]= -11586.0000000000 end for |
6 | nstate[0]= -12197.0159733968 nstate[1]= -11260.0000000000 nstate[2]= -32240.0000000000 nstate[3]= -22153.0000000000 end for |
7 | nstate[0]= 20980.0000000000 nstate[1]= -21632.0000000000 nstate[2]= 0.0000000000 nstate[3]= 3568.0000000000 end for |
8 | nstate[0]= 1824.0000000000 nstate[1]= 0.0000000000 nstate[2]= 0.0000000000 nstate[3]= 0.0000000000 end for |
9 | nstate[0]= 0.0000000000 nstate[1]= 0.0000000000 nstate[2]= 0.0000000000 nstate[3]= 0.0000000000 end for |
10 | nstate[0]= 0.0000000000 nstate[1]= 0.0000000000 nstate[2]= 0.0000000000 nstate[3]= 0.0000000000 end for |
11 | nstate[0]= 0.0000000000 nstate[1]= 0.0000000000 nstate[2]= 0.0000000000 nstate[3]= 0.0000000000 end for |
12 | nstate[0]= 0.0000000000 nstate[1]= 0.0000000000 nstate[2]= 0.0000000000 nstate[3]= 0.0000000000 end for |
13 | nstate[0]= 0.0000000000 nstate[1]= 0.0000000000 nstate[2]= 0.0000000000 nstate[3]= 0.0000000000 end for |
14 | nstate[0]= 0.0000000000 nstate[1]= 0.0000000000 nstate[2]= 0.0000000000 nstate[3]= 0.0000000000 end for |
15 | nstate[0]= 0.0000000000 nstate[1]= 0.0000000000 nstate[2]= 0.0000000000 nstate[3]= 0.0000000000 end for |
16 | nstate[0]= 0.0000000000 nstate[1]= 0.0000000000 nstate[2]= 0.0000000000 nstate[3]= 0.0000000000 end for |
17 | nstate[0]= 0.0000000000 nstate[1]= 0.0000000000 nstate[2]= 0.0000000000 nstate[3]= 0.0000000000 end for |
18 | nstate[0]= 0.0000000000 nstate[1]= 0.0000000000 nstate[2]= 0.0000000000 nstate[3]= 0.0000000000 end for |
19 | nstate[0]= 0.0000000000 nstate[1]= 0.0000000000 nstate[2]= 0.0000000000 nstate[3]= 0.0000000000 end for |
Kann mir damit niemand helfen? Ich denke der Fehler wird irgendein Overflow sein. Ich kann ihn nur nicht finden!!
Pack dein Programm in den Debugger, und steppe da Schritt für Schritt durch. Da musst du selber durch, die Arbeit nimmt die keiner ab. Oliver
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.