Escolar Documentos
Profissional Documentos
Cultura Documentos
Trabalho 2
27 de novembro de 2023
Sumário
I Introdução . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
I - a) Objetivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
II Metodologia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
II - a) IHM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
II - b) Inicialização . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
II - c) Loop Principal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
II - d) Entrada do Encoder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
II - e) Controle da velocidade do motor . . . . . . . . . . . . . . . . . . . . . . . 7
III Simulação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
IV Algoritmo Completo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
Algoritmos
1 Inicialização dos componentes utilizados na planta para IHM . . . . . . . . . . 3
2 Inicialização do microcontrolador ATMega328 . . . . . . . . . . . . . . . . . 4
3 Código do Loop principal do microcontrolador . . . . . . . . . . . . . . . . . 5
4 Configuração das interrupções invocadas pelos pulsos do Encoder . . . . . . . 6
5 Configuração do Timer 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
6 Algoritmo de controle invocado pelo overflow do Timer 1 . . . . . . . . . . . . 8
7 Código do ATmega328P para controle de velocidade de uma máquina CC . . . 10
I Introdução
I Introdução
Neste projeto, foi desenvolvida uma proposta de compensador PI para o fechamento da
malha de velocidade da máquina JGA25-370. O compensador foi inicialmente projetado no
domı́nio contı́nuo e posteriormente discretizado a uma taxa de amostragem de 100Hz, utilizando
o método ”ZOH”(zero-order-hold).
A intuito deste trabalho consiste na reprodução experimental do controle de velocidade em
malha fechada para a mencionada máquina utilizando o controlador ATMega328, conforme
abordado na teoria de Realimentação de Sistemas Dinâmicos. O código projetado para a
implementação prática do controle de velocidade incorporou diversas caracterı́sticas associadas
à planta do sistema, como por exemplo: (i) um Display LCD, (ii) um keypad, (iii) Ponte H para
acionamento, entre outros.
I - a) Objetivos
2
II Metodologia
II Metodologia
II - a) IHM
1 // Keypad Library
2 #include <Keypad_I2C.h>
3 #include <Keypad.h>
4 #include <Wire.h>
5 #define KEYPAD_ADDR 0x20
6
7 // LCD Library
8 #include <LiquidCrystal_I2C.h>
9 #define LCD_col 16
10 #define LCD_lin 4
11 #define LCD_ADDR 0x38
12
13 // ============ Keypad Config ==================================== //
14 const uint8_t ROWS = 4; // number of keypad lines
15 const uint8_t COLS = 4; // number of keypad columns
16 uint8_t keys[ROWS][COLS] = { // key specification
17 {’1’,’2’,’3’,’A’},
18 {’4’,’5’,’6’,’B’},
19 {’7’,’8’,’9’,’C’},
20 {’*’,’0’,’#’,’D’}
21 };
3
II Metodologia
II - b) Inicialização
4
II Metodologia
19 Serial.println(rpsConversion);
20 timerCounter = inputCounter = 0;
21 velocityRef = velocity = 0;
22 direction = None;
23 char key;
24 uint32_t time = 1;
25 // ================================================
26 sei(); // enable global interrupts
II - c) Loop Principal
1 while(1){
2 key = kpd.getKey();
3 if (key != NO_KEY){
4 switch (key)
5 {
6 case ’2’:
7 // Turn the motor off
8 lcd.setCursor(16-3,0);
9 lcd.print("OFF");
10 PORTB &= ˜(1<<PB0); // Set PB0 to 0
11 break;
12 case ’1’:
13 // Turn the motor on
14 lcd.setCursor(16-3,0);
15 lcd.print("ON ");
16 PORTB |= (1<<PB0); // Set PB0 to 1
17 break;
18 case ’A’:
19 // Increase the reference velocity
20 velocityRef += SPD_STEP;
21 if (velocityRef > MAX_SPD) velocityRef = MAX_SPD;
22 break;
5
II Metodologia
23 case ’B’:
24 // Decrease the reference velocity
25 velocityRef -= SPD_STEP;
26 if (velocityRef < MIN_SPD) velocityRef = MIN_SPD;
27 break;
28 default:
29 break;
30 }
31 }
32 if(millis() - time > 500){
33 // Print the velocity and the reference velocity
34 PORTB ˆ= (1<<PB5);
35 time = millis();
36 lcd.setCursor(16+4,0);
37 lcd.print(velocity);
38 lcd.setCursor(16+9,0);
39 lcd.print(" | ");
40 lcd.setCursor(16+12,0);
41 lcd.print(velocityRef);
42 }
43 }
II - d) Entrada do Encoder
1 /**
2 * @brief Configure the input INT0 and INT1 interrupts
3 */
4 void configInput(){
5 // Set the interrupt to trigger on the falling edge and rising edge
6 EICRA = (1 << ISC10) | (1 << ISC00);
7 // Enable interrupts for INT0 and INT1
6
II Metodologia
8 EIMSK = (1<<INT0)|(1<<INT1);
9 }
10 // Interrupt Service Routines for INT0
11 ISR(INT0_vect){
12 // Register the motor encoder input on the rising edge and falling
edge at the input INT0
13
14 inputCounter++;
15 // INT0-> PD2 (pin 2 of the Arduino connector)
16 if (PIND & (1<<PD2)){
17 // If the input 2 and 3 are high the motor is moving forward
18 if (PIND & (1<<PD3)) direction = Forward;
19 else direction = Backward;
20 }
21 }
22
23 // Interrupt Service Routines for INT1
24 ISR(INT1_vect){
25 // Register the motor encoder input on the rising edge and falling
edge at the input INT1
26 inputCounter++;
27 }
A operação que estima o número de bordas registradas pelo encoder e converte para a
velocidade do eixo em RPM, é invocada pela interrupção de hardware do Timer 1, ele foi
configurado de modo que a cada 0,2ms ele interrompe o microcontrolador por causa do overflow
e executa a função ISR(TIMER1 COMPA vect). O código da configuração do Timer 1 é
mostrado no Algoritmo 5.
1 /**
2 * @brief Configure the timer 1
3 * @param comp_A Compare value for the output A
4 * @param comp_B Compare value for the output B
5 */
6 void configTimer1(uint16_t comp_A, uint16_t comp_B){
7
II Metodologia
7 /*
8 Config Timer 1
9 - Wave Generation Mode 10 (PWM Phase Correct)
10 - Compare Output Mode 1A (Clear on Compare Match, Set at BOTTOM)
11 - Compare Output Mode 1B (Clear on Compare Match, Set at BOTTOM)
12 - Clock speed 16MHz
13 */
14 TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM11); // Set the
compare output mode for A and B
15 TCCR1B = (1 << WGM13) | (1 << CS10); // Set the wave generation mode
and the clock speed
16 // Set the compare values for input A and B
17 OCR1A = comp_A; OCR1B = comp_B;
18 TIMSK1=0x01; // enable overflow interrupt
19 ICR1=1600; // 16MHz/1600=10kHz
20 TCNT1=0; // clear the timer counter
21 }
8
III Simulação
15 timerCounter++;
16 if (timerCounter >= 50){
17 // Compute the velocity and the PI controller output
18 timerCounter = 0;
19 velocity = (float)inputCounter*rpsConversion*direction;
20 inputCounter = 0;
21 voltage_PI = voltage_PI + (PI_B0 * (velocityRef - velocity) + PI_B1
* PI_Error)*6.2831853;
22 if (voltage_PI > 10.8) voltage_PI = 10.8;
23 else if (voltage_PI < -10.8) voltage_PI = -10.8;
24 PI_Error = (velocityRef - velocity);
25
26 comp_A = 800 + (uint16_t)(voltage_PI*66.6666667);
27 OCR1A = comp_A;
28 OCR1B = 1600 - comp_A;
29 }
30 }
III Simulação
A planta do sistema foi simulada no software Proteus, o esquemático utilizado é mostrado
na Figura 1.
LP0
LP1
LP2
LP4
LP5
LP6
LP7
12
13
14
11
1
2
3
4
5
6
7
8
9
U2 LM041L
14 4
Dual Bridge Motor
VSS
VEE
RS
D0
D1
D2
D3
D4
D5
D6
D7
VDD
RW
IN3
Reset BTN
DB_ENA ENA
11 ENB OUT3 13
AREF
KP4 A 1 2 3 A 13 1 SENSA OUT4 14
PB5/SCK 15
PB4/MISO 12 SENSB GND
RESET 11
U1 ~ PB3/MOSI/OC2A
SCL 14 SCL P0 4 KP0
KP5 B 4 5 6 B ~ PB2/OC1B
~ PB1/OC1A
10
9 DB_IN2
8 L298
SDA 15 SDA P1 5 KP1 8 DB_IN1
6 PB0/ICP1/CLKO
P2 KP2 DB_ENA
ATMEGA328P-PU
13 7
8
1121
PD7/AIN1 7
P4 9 KP4 6
1 10 A0 ~ PD7/AIN1
A0 P5 KP5 PC0/ADC0 5
2
3
A1
A2
P6
P7
11
12
KP6
KP7 KP7 D * 0 # D
A1
A2
PC1/ADC1
PC2/ADC2
~ PD5/T1/OC0B
PD4/T0/XCK
~ PD3/INT1/OC2B
4
3 ENCODER B
Motor ENCODER B
ENCODER A
SDA A3 PC3/ADC3 PD2/INT0 2
PCF8574 A4 PC4/ADC4/SDA 1
PD1/TXD
1
A5 PC5/ADC5/SCL 0 ENCODER A
PD0/RXD
SCL DB_OUT1 DB_OUT2
9
IV Algoritmo Completo
IV Algoritmo Completo
O algoritmo completo do código implementado no ATMega328 é mostrado no Algoritmo 7.
1 // Keypad Library
2 #include <Keypad_I2C.h>
3 #include <Keypad.h>
4 #include <Wire.h>
5 #define KEYPAD_ADDR 0x20
6
7 // LCD Library
8 #include <LiquidCrystal_I2C.h>
9 #define LCD_col 16
10 #define LCD_lin 4
11 #define LCD_ADDR 0x38
12
13 /*
14 PI Controller
15 - PI_B0: Proportional gain
16 - PI_B1: Derivative gain
17 - PulsePerRevolution: Number of pulses per revolution of the motor
18 - MAXSPD: Maximum velocity of the motor
19 - MINSPD: Minimum velocity of the motor
20 - Equation:
21 - G(z) = (PI_B0 * ( z - PI_B1 ) ) / (z-1)
22 - Voltage = Voltage_dot + PI_B0 * Error + PI_B1 * Error_dot
23 */
24 #define PI_B0 0.4556
25 #define PI_B1 -0.2419
26 const float PulsePerRevolution = 4*11*45; // (4 INTS per encoder pulses)
* (11 Encoder pulses per revolution) * (45 gearbox ratio)
27 #define MAX_SPD 2.0
28 #define MIN_SPD -2.0
29 #define SPD_STEP 0.2
30
31 enum Direction_E{
32 Forward = 1,
33 Backward = -1,
10
IV Algoritmo Completo
34 None = 0
35 };
36
37 void printHome();
38 void configTimer1(uint16_t comp_A, uint16_t comp_B);
39 void configInput();
40
41 // ============ Keypad Config ====================================
42 const uint8_t ROWS = 4; // number of keypad lines
43 const uint8_t COLS = 4; // number of keypad columns
44 uint8_t keys[ROWS][COLS] = { // key specification
45 {’1’,’2’,’3’,’A’},
46 {’4’,’5’,’6’,’B’},
47 {’7’,’8’,’9’,’C’},
48 {’*’,’0’,’#’,’D’}
49 };
50 uint8_t rowPins[ROWS] = {4, 5, 6, 7}; //connection to the row pinouts of
the keypad
51 uint8_t colPins[COLS] = {0, 1, 2, 3}; //connection to the column pinouts
of the keypad
52 TwoWire *jwire = &Wire;
53 Keypad_I2C kpd(makeKeymap(keys), rowPins, colPins, ROWS, COLS,
KEYPAD_ADDR, PCF8574, jwire);
54
55 // ========== LCD Config =======================================
56 LiquidCrystal_I2C lcd(LCD_ADDR,LCD_col,LCD_lin);
57
58 // ========== Global Variables ==================================
59 uint16_t inputCounter, timerCounter, comp_A;
60 float velocity, rpsConversion, PI_Error, voltage_PI, velocityRef;
61 Direction_E direction;
62
63 int main(){
64
65 cli(); // disable global interrupts
66 // ============ ATMega Initiate ====================================
67 init(); // Call ATMega initialization functions
68
69 // Initiate the peripherals
11
IV Algoritmo Completo
12
IV Algoritmo Completo
13
IV Algoritmo Completo
14
IV Algoritmo Completo
179 */
180 void configInput(){
181 // Set the interrupt to trigger on the falling edge and rising edge
182 EICRA = (1 << ISC10) | (1 << ISC00);
183
184 // Enable interrupts for INT0 and INT1
185 EIMSK = (1<<INT0)|(1<<INT1);
186 }
187
188 // Interrupt Service Routines for INT0
189 ISR(INT0_vect){
190 // Register the motor encoder input on the rising edge and falling
edge at the input INT0
191
192 inputCounter++;
193
194 // INT0-> PD2 (pin 2 of the Arduino connector)
195 if (PIND & (1<<PD2)){
196 // If the input 2 and 3 are high the motor is moving forward
197 if (PIND & (1<<PD3)) direction = Forward;
198 else direction = Backward;
199 }
200 }
201
202 // Interrupt Service Routines for INT1
203 ISR(INT1_vect){
204 // Register the motor encoder input on the rising edge and falling
edge at the input INT1
205 inputCounter++;
206 }
207
208 // Interrupt Service Routines for Timer 1
209 ISR(TIMER1_OVF_vect){
210 /*
211 This interrupt is called every 0.2ms (5kHz) and when it’s counter
reaches 50,
212 it computes the velocity of the motor and the PI controller output,
updating the
213 compare value for the output A and B
15
IV Algoritmo Completo
214 */
215 timerCounter++;
216 if (timerCounter >= 50){
217 // Compute the velocity and the PI controller output
218 timerCounter = 0;
219 velocity = (float)inputCounter*rpsConversion*direction;
220 inputCounter = 0;
221 voltage_PI = voltage_PI + (PI_B0 * (velocityRef - velocity) + PI_B1
* PI_Error)*6.2831853;
222 if (voltage_PI > 10.8) voltage_PI = 10.8;
223 else if (voltage_PI < -10.8) voltage_PI = -10.8;
224 PI_Error = (velocityRef - velocity);
225
226 comp_A = 800 + (uint16_t)(voltage_PI*66.6666667);
227 OCR1A = comp_A;
228 OCR1B = 1600 - comp_A;
229 }
230 }
16