vel_control.c 8.94 KB
Newer Older
Pontus Giselsson's avatar
Pontus Giselsson committed
1
2
/*
**************************************************************
3
4
5
6

 Current regulation - Pontus Giselsson, Per-Ola Larsson 18/02/09
           for LTH - reglerteknik

Pontus Giselsson's avatar
Pontus Giselsson committed
7
8
***************************************************************
*/
9
#include <util/twi.h>
10
11
12
#include <avr/io.h>
#include <avr/interrupt.h>
#include <inttypes.h>
13
#include <compat/deprecated.h>
14

15
16
17
18
#include "pccom.h"
#include "vel_control.h"


19
// reference variables
20
volatile int32_t ref = 0;        // 11 frac bits (variable in mm/s, max 2^12)
21
volatile int32_t refCtrl = 0;    // ref used in ctrl-loop (=ref sent from simulink)
22
23
volatile int32_t aRef = 0;       // 14 frac bits (variable in mm/s, max 2^15)
volatile uint16_t nbrSamples = 0; // nbr of samples between ctrl-ref updates
24
25

// velocity control variables
26
27
28
29
30
31
32
33
34
35
volatile int32_t u = 0;          // 11 frac bits
volatile int32_t uSend = 0;      // ctrl sent to simulink
volatile int32_t v = 0;          // 11 frac bits
volatile int32_t vSat = 0;
volatile int8_t brake = 0;       // brake variable if pos-sample missed
volatile int32_t I = 0;          // 11 frac bits
volatile int32_t e = 0;          // 11 frac bits
volatile int8_t intCond = 0;


Pontus Giselsson's avatar
Pontus Giselsson committed
36
37
volatile int32_t K = 807;       // 6 frac bits, prop constant
volatile int32_t Ke = 13;        // 6 frac bits, integral constant
38
volatile int8_t fr_comp = (10<<3);
Pontus Giselsson's avatar
Pontus Giselsson committed
39
40
#define V_MAX (120<<4)
#define V_MIN (-120<<4)
41

42
43

// encoder variables
44
#define ENCODERY  (PIND&0x04)        //Positional encoder pins
45
46
47
48
49
50
51
52
53
54
55
#define ENCODERX  ((PINB&0x02)<<1)   //Positional encoder pins (shift one step for faster comparison with Y)

// position variables
volatile int16_t pos = 0;        // position in tics
volatile int16_t posTemp = 0;    // position sent to simulink
volatile int16_t posCtrl = 0;    // position used in ctrl-loop
volatile int16_t oldPos = 0;     // previous pos used for velocity estimation
volatile int8_t newX;            // encoder signal
volatile int8_t newY;            // encoder signal
volatile int8_t oldX;            // previous encoder signal
volatile int8_t oldY;            // previous encoder signal
56
57

// velocity estimation parameters
58
59
60
61
volatile int32_t velEst = 0;     // vel-estimate, 5 frac bits
volatile int32_t velEstSend = 0; // vel-estimate sent to simulink
int16_t a = 116;                 // 7 frac bits (parameter in velocity estimate)
int16_t b = 152;                 // 5 frac bits (parameter in velocity estimate)
62

63
// adc measurement variables
64
65
66
67
68
volatile int16_t low;            // temporary variable for ad-reading
volatile int16_t high;           // temporary variable for ad-reading
volatile int16_t angleOffset = 0;

/* return position (in tics) */
69
int32_t getPosition() {
70
  cli();
71
  posTemp = pos;
72
  sei();
73
  return ((int32_t) posTemp);
74
75
76
}


77
/* return velocity (in mm/s) */
78
int32_t getVelocity() {
79
80
81
  return velEstSend;
}

82
83

/* return last angle measurement */
84
85
86
int16_t getAngle() {
  low = inp(ADCL);
  high = inp(ADCH);
87
  return (((int16_t) ((high<<8) | low) - 512)-angleOffset);
88
89
}

90
91

/* return current-reference */
92
93
int32_t getCurrentRef() {
  return uSend;
94
95
}

96

97
98
99
100
101
102
103
104
105
106
/* Set new acceleration reference value */
void setAccRef(int32_t newAccRef) {
  aRef = newAccRef;
  nbrSamples = 0;
}


/* Set new velocity reference value */
void setVelRef(int32_t newVelRef) {
  ref = newVelRef;
107
108
}

109
110
111
112
113
114
115
/* Routine used to initialize the positional encoders */
void initPos()
{
  oldX = ENCODERX;
  oldY = ENCODERY;
}

116
/* Timer 2, Encoder counter, 73 kHz updates position variable */
117
SIGNAL(TIMER2_COMP_vect) {
118

119
120
121
  // Update position from encoder
  newX = ENCODERX;
  newY = ENCODERY;
122
123
  if((newX != oldX) || (newY != oldY)) {                            //Check if any value changed
      /*
124
125
      sum = (oldX<<2)+oldY+newX+(newY>>2);  
      if (sum == 2 || sum == 4 || sum == 11 || sum == 13) {
126
	pos = pos+1;
127
      } else if (sum == 1 || sum == 7 || sum ==  8 || sum == 14) {
128
129
130
131
132
	pos = pos-1;
      } else {
	brake = 1; // emergency brake
      }
      */
133
    // Works like if-clauses above, but faster!
134
135
136
137
      if ((oldX == newY) && (oldY != newX)) {
	pos = pos+1;
      } else if ((oldX != newY) && (oldY == newX)) {
	pos = pos-1;
138
139
140
141
142
      } else {
	brake = 1;
      }
      oldX = newX;
      oldY = newY;
143
144
145
146
147
  }

}


148
/* Timer 0, serial communication with simulink */
149
SIGNAL(TIMER0_COMP_vect) {
150

151
  TIMSK &= ~(_BV(OCIE0)|_BV(OCIE1A));   // Disable communication and ctrl-interrupts
152
153

  sei(); // enable interrupts from encoder-counter
Pontus Giselsson's avatar
Pontus Giselsson committed
154
  
155
  // Poll UART receiver
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
  uint8_t status = UCSRA;
  if (status & (1<<RXC)) {
    char ch = UDR;
    pccom_receiveByte(ch);
    
    if (status & ((1<<FE)|(1<<DOR)|(1<<PE))) { 
      //main_emergencyStop(); // stop on USART error
    }     
  }
  
  // Poll UART sender
  if (UCSRA & (1<<UDRE)) {
    int16_t toSend = pccom_getNextByteToSend();
    if (toSend >= 0) UDR = (char)toSend;
  }
Pontus Giselsson's avatar
Pontus Giselsson committed
171

172
  TIFR = (1<<OCF0);        // skip pending interrupts from serial comm, (but not from ctrl)
173

174
  TIMSK |= (_BV(OCIE0)|_BV(OCIE1A)); // reenable communication and ctrl-interrupts
175

176
177
178
179
}



180
/* Timer 0, control loop , 1 kHz */
181
SIGNAL(TIMER1_COMPA_vect) {
182
  
183
  posCtrl = pos; // store pos to use in this loop
184

185
  sei(); // to enable interupts from encoder counter and communication
186

187
  // velocity estimation in mm/s
188
189
190
  velEst = (((a*velEst+64)>>7)+b*(posCtrl-oldPos));  // 5 fracbits on velEst
  oldPos = posCtrl;
  
191
  // store velEst and ref to be sent/used here
192
193
  cli();
  velEstSend = velEst;
194
195
196
197
198
  nbrSamples++;
  refCtrl = ref+((aRef*nbrSamples)>>10);  //shift nbrSamples 10 steps (= nbrSamples*h)
  if (nbrSamples > 500) {
    refCtrl = 0;   // for safety reasons if doesn't send anything in 0.5 s
  }
199
  // ref = ref*(1-brake); // emergency stop
200
  sei();
201
202

  // control error
203
  e = refCtrl-((velEst+16)>>5);  // mm/s
204

205
206
  // temporary ctrl-signal
  v = (((K*e+(1<<5))>>6)+((I+(1<<3))>>4));
207
208

  // friction compensation
209
  if (refCtrl > 0) {
210
211
212
    v = v+fr_comp;
  } else if (refCtrl < 0) {
    v = v-fr_comp;
213
214
  }

215
216
217
218
219
220
221
222
223
224
225
226
227
228
  // variable that decides if I-part should be updated
  intCond = 1;
  
  // saturation of v
  if (v > V_MAX) {
    vSat = V_MAX;
    if (e > 0)
      intCond = 0;
  } else if (v < V_MIN) {
    vSat = V_MIN;
    if (e < 0)
      intCond = 0;
  } else {
    vSat = v;
229
  }
230
231
232
233
234
  
  if (intCond)
    I = I + (((Ke*e)+(1<<1))>>2);

  // scale ctrl-signal to send over twi
Pontus Giselsson's avatar
Pontus Giselsson committed
235
  u = (vSat+8)>>4; // u=127 gives current = 6.75 A, vSat makes u saturate at 114
236

237
  // u that is sent to simulink
238
239
240
  cli();
  uSend = u;
  sei();
241

Pontus Giselsson's avatar
Pontus Giselsson committed
242

243
  // TWI-communication to set current reference on the other atmel
244
  // send start command
245
246
  outp(_BV(TWINT)|_BV(TWEN)|_BV(TWSTA),TWCR);
  while (!(TWCR&_BV(TWINT))) {}
247
    
248
249
  // Contact slave  
  outp(0x02,TWDR);  // slave is 0x02 (sla+w)
250
251
  outp(_BV(TWINT)|_BV(TWEN),TWCR);
  while (!(TWCR&_BV(TWINT))) {}
252
253
254
 
  // Send reference byte to slave
  outp((int8_t)u,TWDR);  // send 8 bits reference
255
256
  outp(_BV(TWINT)|_BV(TWEN),TWCR);
  while (!(TWCR&_BV(TWINT))) {}
Pontus Giselsson's avatar
Pontus Giselsson committed
257
    
258
  // stop transmission
259
  outp(_BV(TWINT)|_BV(TWEN)|_BV(TWSTO),TWCR);
260
261
262
263
264
265
266
267
268

}


int main()
{
  cli();
  
  //Port directions
269
  //outp(0x80,DDRB);   // Led output
270
  outp(0x10,DDRC);  // timer calculation port
271
272
273
  PORTD = 0x40;  // pull up on reset switch


274
  /* Timer section */
275
  // Enable timer0, timer1, timer2 compare match interrupts
276
  outp(_BV(OCIE0)|_BV(OCIE1A)|_BV(OCIE2),TIMSK);
277
  
278
  /* Timer 2, 73 kHz Prescaler 1, encoder counter for position measurement */
279
  outp(_BV(WGM21)|_BV(CS20),TCCR2);
280
281
282
  outp(200,OCR2);
  /* Reset timer 2 */
  outp(0,TCNT2);
283
  
284
  /* Timer 1, 1 kHz , prescaler 1, ctrl-loop */
285
286
287
  outp(_BV(WGM12)|_BV(CS10),TCCR1B);
  outp(0x38,OCR1AH);
  outp(0x3f,OCR1AL);
288
289
290
291
  outp(0,TCNT1H);
  outp(0,TCNT1L);
  

Pontus Giselsson's avatar
Pontus Giselsson committed
292
  /* Timer 0, 40 kHz, Prescaler 8, serial communication */
293
  outp(_BV(WGM01)|_BV(CS01),TCCR0);
Pontus Giselsson's avatar
Pontus Giselsson committed
294
  //outp(184-1,OCR0); // 10 kHz
295
  outp(45-1,OCR0); // 40 kHz
Pontus Giselsson's avatar
Pontus Giselsson committed
296
   /* Reset timer 0 */
297
298
  outp(0,TCNT0);

299
300

  // syncronization (ctrl interrupt 34 micros before communication interrupt)
301
  TCNT1 = TCNT0*8+500;
302
303
  
  
304
  //Serial communication initialization
305
  outp(0x00, UCSRA);	// USART:
306
  outp(0x18, UCSRB);	// USART: RxEnable|TxEnable
307
308
  outp(0x86, UCSRC);	// USART: 8bit, no parity
  outp(0x00, UBRRH);	// USART: 115200 @ 14.7456MHz
309
  outp(7,UBRRL);	// USART: 115200 @ 14.7456MHz 
310
  
311
312
  
  /* AREF (AREF is 5V) pin external capacitor, ADC3 for pendulum angle */
313
  outp(_BV(REFS0)|_BV(MUX0)|_BV(MUX1),ADMUX);
314
  
315
  // Enable ADC on adc3, start first conversion, prescaler 128, free running mode
316
  outp(_BV(ADEN)|_BV(ADSC)|_BV(ADATE)|_BV(ADPS2)|_BV(ADPS1)|_BV(ADPS0),ADCSRA);
317
318
319
320


  // Initialize Master TWI
  outp(0x10,TWBR);  // set SCL-frequency CPU-freq/(16+2*16)
321
  outp(_BV(TWEN),TWCR); // enable TWI
322
323
324

  // initialize position measurements
  initPos();
325

326
  // initialize pc-communication
327
  pccom_init();
328
329
330
331
332
  
  //Enable interrupts
  sei();

  // loop
333
334
335
336
337
338
339
340
341
342
343
344
  while (1) {
    // reset position, velocity estimate and integral part of ctrl if reset button pushed
    if (!(PIND & 0x40)) {
      cli();
      low = inp(ADCL);
      high = inp(ADCH);
      pos = 0; // reset position
      angleOffset =  ((int16_t) ((high<<8) | low) - 512);
      oldPos = 0;
      velEst = 0; // reset velocity estimate
      I = 0; // reset integral part of controller
      u = 0; // reset ctrl signal
Pontus Giselsson's avatar
Pontus Giselsson committed
345
      sei();
346
347
    } 
  }
348
}