Controle de Motor BLDC INPE
Controle de Motor BLDC INPE
Controle de Motor BLDC INPE
discussions, stats, and author profiles for this publication at: https://www.researchgate.net/publication/317019440
PROJETO E DESENVOLVIMENTO DE UM
CONTROLADOR DE MOTORES "BRUSHLESS"
(BLDC) PARA APLICAÇÃO...
CITATIONS READS
0 299
1 author:
SEE PROFILE
Some of the authors of this publication are also working on these related projects:
All content following this page was uploaded by Fernando De Almeida Martins on 19 May 2017.
PROJETO E DESENVOLVIMENTO DE UM
CONTROLADOR DE MOTORES "BRUSHLESS" (BLDC)
PARA APLICAÇÃO EM VOLANTES DE INÉRCIA
INPE
São José dos Campos
2014
PUBLICADO POR:
PROJETO E DESENVOLVIMENTO DE UM
CONTROLADOR DE MOTORES "BRUSHLESS" (BLDC)
PARA APLICAÇÃO EM VOLANTES DE INÉRCIA
INPE
São José dos Campos
2014
Dados Internacionais de Catalogação na Publicação (CIP)
Esta obra foi licenciada sob uma Licença Creative Commons Atribuição-NãoComercial 3.0 Não
Adaptada.
This work is licensed under a Creative Commons Attribution-NonCommercial 3.0 Unported Li-
cense.
ii
“Estudar é um ato político”.
F. Martins
v
vi
Aos que ainda acreditam que a educação é a força máxima de um país.
vii
viii
AGRADECIMENTOS
ix
x
RESUMO
xi
xii
DESIGN AND CONSTRUCTION OF A MOTOR CONTROLLER
"BRUSHLESS" (BLDC) APPLICATION FOR STEERING WHEELS AND
WHEELS OF INERTIA
ABSTRACT
xiii
xiv
LISTA DE FIGURAS
Figura 3.9 - Detalhe da conexão do motor, filtro LC e leitura das tensões das
fases. ................................................................................................................ 23
Figura 3.11 - Motor brushless com a posição dos sensores Hall. .................... 25
xv
Figura 3.13 - Diagram em blocos da interface de comunição. ......................... 26
. ........................................................................................................................ 51
xvi
Figura 5.21 – Curva de velocidade do volante de inércia. ................................ 53
xvii
xviii
LISTA DE SIGLAS E ABREVIATURAS
xix
xx
SUMÁRIO
1. INTRODUÇÃO ........................................................................................... 1
3.6. Sensores.................................................................................................... 23
xxi
5.4. Tempo de decaimento em rotação ............................................................. 48
6. CONCLUSÕES ......................................................................................... 55
xxii
1. INTRODUÇÃO
1
A roda de reação usa o princípio da conservação da quantidade de momento
angular que diz que em um sistema livre de torques externos a quantidade de
momento angular se conserva. De uma forma simplória, pode-se dizer que
rodas de reação são motores elétricos CC dotados de volantes de inércia.
1.1. Objetivo
Este trabalho tem por objetivo projetar e construir um protótipo de uma roda de
reação com características funcionais semelhantes àquelas voltadas para
aplicações espaciais. A roda desenvolvida é capaz de realizar os acionamentos
elétricos de fase para motores de corrente contínua sem escovas (ou BLDC, do
Inglês Brushless DC motor) em diversas configurações de polos e fases para
se criar os fundamentos requeridos pela eletrônica de uma roda de reação.
2
Em resumo, este trabalho apresenta o projeto, desenvolvimento,
implementação e testes de um dispositivo eletrônico composto de um micro-
controlador e uma unidade de FPGA para o controle e acionamento das fases
do motor BLDC, com capacidade de sensoriamento por meio de sensores Hall,
por sensor óptico (encoder), por medição da corrente das fases e medição das
tensões de cada fase. Além da alimentação do motor, foi implementado o
monitoramento remoto e a medição da rotação e da corrente do motor, de
modo a permitir que se controle o funcionamento do motor numa aplicação
típica para uma roda de reação em malha fechada.
1.2. Motivação
3
A dinâmica de um satélite é atitude e sua órbita. A atitude compreende a
posição e velocidade angulares do satélite em torno de seu centro de massa. A
órbita compreende a posição e velocidade do satélite em torno da Terra. A
atitude pode ser afetada por diversos torques que têm origem no meio
ambiente espacial ou gerados internamente pelo próprio satélite. A
determinação da atitude é o processo de computar a orientação do satélite em
relação a um sistema de referência (inercial ou não inercial). Como exemplo
pode-se citar um sistema de referência fixado a algum corpo de interesse, tal
como a Terra. Isso normalmente envolve diversos tipos de sensores em
satélites e sofisticados procedimentos de processamento de dados (WERTZ,
1978). O controle da atitude do satélite é crucial para o adequado desempenho
das suas funções que podem ser sensoriamento remoto, meteorologia e
comunicação, entre outras aplicações (WERTZ, 1978).
4
isso, comprometam a estabilidade do movimento. É bastante comum o
emprego de rodas de reação para esta finalidade, pois elas conseguem suprir
torques numa faixa de 10-5 a 10-1 Nm.
5
Figura 1.1 - Foto do SCD-2 com a Roda de Reação indicada no detalhe.
1.3. Metodologia
6
deverá ser feita manualmente segundo as regras básicas de sintonia
(ÅSTRÖM,1995).
Fonte Chaveada
FPGA Drivers MOSFETS
Microprocessamento
Shunt
BLDC
Sensores Hall
7
8
2. TEORIA DE CONTROLE DO MOTOR BLDC
Para o trabalho proposto, o motor BLDC a ser utilizado será um motor DC sem
escovas convencional acoplado a um volante de inércia com características
semelhantes às de uma roda de reação comercial de fabricação da SunSpace,
-3 2
isto é, momento de inercia próximo a 1.5 x 10 kg.m , rotação entre -4000 e
4000rpm e torque máximo de 50 mNm. O motor utilizado será composto por 4
pares de polos e 3 fases, com uma tensão de alimentação de 12 Volts DC e
uma corrente máxima nominal contínua de 1000mA. Segundo o manual do
fabricante, a inércia do rotor é de 13,9 g cm² e será levada em consideração no
cálculo da massa de inércia total. Além dessas propriedades o motor também
disponibiliza 3 sensores de efeito Hall para o sincronismo no chaveamento das
fases, acoplados ao próprio motor.
9
Os intervalos de comutações, mostrados na Fig. 2.2(b) estão em função do
ângulo de rotação do rotor, cuja comutação é apresentada na Fig. 2.2(a), que
representa as lógicas obtidas pelas leituras dos sensores Halls . Na Fig 2.2(c)
tem-se a forma de onda completa nas bobinas do motor de 3 fases.
H1
H2
H3
Va
Vb
Vc
Vab
Vbc
Vca
Num dado instante, um polo de cada uma das fases é alimentado com tensão
positiva de um lado e o polo oposto é alimentado com tensão negativa (ou
terra), a fim de manter no circuito uma corrente elétrica circulando pela bobina
do motor (fase). Para comutar-se apropriadamente, o controlador tem de
conhecer a posição do sector (intervalo de 15 graus) do ângulo do eixo. As três
10
saídas do sensor Hall, como mostradas na Fig. 2.2(a), são frequentemente
usadas para detectar a posição do eixo.
Este trabalho irá utilizar um motor sem escovas já com os sensores Hall
embutidos no próprio motor, tendo o micro-controlador como o componente
responsável pelo monitoramento da corrente e da rotação, pelo controle do
sinal PWM via um controlador PI (Proporcional, Integral) e pelo sincronismo na
comutação das fases, bem como por disponibilizar os dados por intermédio de
uma interface serial RS232 ou USB.
Uma das partes que requer mais atenção no desenvolvimento deste acionador
será a concepção de um algoritmo que garanta a operação correta nos
acionamentos dos transistores MOSFETS (drivers) em configuração de ponte
H. Isto é necessário para se evitar que uma chave conectada à alimentação
(high side) seja acionada junto com a chave conectada ao terminal de terra
(low side), causando assim um curto-circuito entre a alimentação da tensão e a
linha de terra. No circuito de acinamento foi criado um circuito auxiliar para que
este evento não ocorra e será descrito no capítulo 3.4.
11
Figura 2.3. - Exemplo do fluxo de corrente no acionamento (esquerda) e quando o
transistor superior é desligado (direita).
12
do controlador, que comutará os MOSFETS em frequência do PWM com ciclo
útil (duty cycle) próxima de 4 kHz, de acordo com a necessidade de atuação
exigida pelo algoritmo de controle. Consegue-se, assim, por meio de uma
tensão média gerada pelo PWM, a intensidade de corrente necessária para
propiciar uma velocidade de rotação estipulada pelo controle externo da roda
de reação por meio da interface serial. Um fluxograma simplificado do controle
efetuado pelo micro-controlador é mostrado na Fig. 2.5.
13
14
3. PROJETO DA ELETRÔNICA DE CONTROLE
A Fig 3.1 mostra a placa eletrônica já finalizada e montada, cujo projeto será
descrito nas próximas seções. Mais detalhes podem ser encontrados no
Apêndice A, que apresenta o esquema elétrico do circuito eletrônico de
acionamento.
15
O projeto do controlador permitirá programar o acionamento do motor tanto em
linguagem C usando o microcontrolador como também em linguagem VHDL
utilizando um componente FPGA (do inglês Field-Programmable Gate Array, ou
arranjo de portas programável em campo, de nome Altera Cyclone II).
16
3.1. FPGA
A Fig. 3.3 ilustra o diagrama elétrico parcial do FPGA projetado, no qual são
definidos os terminais de conexão entre o microcontrolador e as entradas e
saídas dos sinais.
17
FPGA
Acionamento dos
MOSFETS
Sensores Hall
Encoders Óticos
Porta Paralela p/
Micro-controlador troca de informações
3.2. Microcontroladores
18
Um dos micro-controladores usado é o de núcleo M4 de 32bits com frequência
de 120 MHz fabricado pela Atmel. Seu código é ATMEL ARM SAM4S. Esse
micro-controlador é capaz de adquirir todas as informações analógicas dos
sensores de corrente do motor por meio de 16 entradas analógicas de 12 bits e
também possui entradas para sinais digitais dos sensores de rotação, tanto o
codificador óptico (encoder) quanto o sensor de efeito Hall.
Micro-controlador
Sinais de entrada Acionamento dos
analógicos MOSFETS (via FPGA)
(corrente do motor)
Sensores Hall
Comunicação Serial Encoders Óticos
ICSP (via FPGA)
Memória Flash
Porta Paralela p/
troca de informações FPGA
19
Este processador foi escolhido devido à facilidade de se encontrar e usar as
ferramentas de software e hardware para programação e depuração. O
esquema elétrico das conexões deste micro-controlador é ilustrado na Figura
3.5.
Micro-controlador
Sinais de entrada Acionamento dos
analógicos MOSFETS (via FPGA)
(corrente do motor)
Sensores Hall
Comunicação Serial Encoders Óticos
ICSP (via FPGA)
Memória Flash
Porta Paralela p/
troca de informações FPGA
3.3. MOSFETS
20
FASE-A FASE-B FASE-C FASE-D FASE-E
+VCC
Q7 Q8 Q9 Q10 Q11
3 3 3 3 3
4 4 4 4 4
AT BT CT DT ET
5, 6 5, 6 5, 6 5, 6 5, 6
1 1 1 1 1
2 2 2 2 2
AB BB CB DB EB
7, 8 7, 8 7, 8 7, 8 7, 8
IRF7319TRPBF IRF7319TRPBF IRF7319TRPBF IRF7319TRPBF IRF7319TRPBF
R80
0R1
Resistor Shunt
Essa proteção é de grande importância quando se tem uma placa que será
usada em ensaios e testes, na qual o software que controla os transistores
MOSFET é executado fora das bases de tempo do micro-controlador, em um
processo de debug, por exemplo.
21
U2C
9
EN-B
8
PRE-BT
10
T/B-B
MM74HCT08M
U3B
U2D
3 4 12
11
PRE-BB
13
MM74HCT04M
MM74HCT08M
+VCC
R8
10K ; 5%
BT R7
PRE-BB BB
3
R10 1 Q2 R9
PRE-BT 100R ; 5%
BC817
100R ; 5% 10K ; 5%
2
22
+5V
CN10
1
R83 1K ; 5% 2
HALL1 1K ; 5%
R84 3
HALL2 1K ; 5%
R85 4
HALL3
5
L2
744901110 6
FASE-A
7
L3
744901110 8
FASE-B
9
L4
744901110 10
FASE-C
11
L5
744901110 12
FASE-D
13
L6
744901110 14 16
FASE-E
15 17
R86
R87
R88
R89
R90
C76 C77 C78 C79 C80 52207-1590
100nF
100nF
100nF
100nF
100nF
8K2 ; 5%
8K2 ; 5%
8K2 ; 5%
8K2 ; 5%
8K2 ; 5%
R91 1K ; 5%
VA
R92 1K ; 5%
VB
R93 1K ; 5%
VC
R94 1K ; 5%
VD
R95 R100 1K ; 5%
R96
R97
R98
R99
VE
1K ; 5%
1K ; 5%
1K ; 5%
1K ; 5%
1K ; 5%
Figura 3.9 - Detalhe da conexão do motor, filtro LC e leitura das tensões das fases.
3.6. Sensores
23
FASE-E
Q11 +VCC
3
4
ET
5, 6 +3V3A
1
2 R77 C75
EB 47K ; 5%
7, 8
IRF7319TRPBF
+3V3A
100nF
7
R78 3
6 R79
R80 R81 1 I-FASE
2
Resistor Shunt 0R1 1K ; 5% U16
NC MCP601-I/SN 1K ; 5%
R82
4
1K ; 5%
24
Figura 3.11 - Motor brushless com a posição dos sensores Hall.
Fonte: Maxon Motor (2014).
+5V +5V
+5V
R101 R102
R103
330R ; 5%
330R ; 5%
PHOTO-A PHOTO-B
330R ; 5%
Q12 Q13
D10
PT19-21B PT19-21B
CONEXÃO ENCODER
PHOTO-A
PHOTO-B +5V
CN8
10k ; 5% 1
R54
ENC-A 10k ; 5% 2
R55
ENC-B 10k ; 5% 3
R56
ROT 4
5
619 005 111 21
R58
R59
R60
10k ; 5%
10k ; 5%
10k ; 5%
25
Para a indicação de sentido de rotação, além do sensor de efeito Hall, também
será disponibilizada uma entrada para encoders digitais que podem ou não ser
incorporados ao disco graduado. Por fim, uma entrada extra para mais um
sensor hall estará disponível, que poderá ser usada caso o rotor de inércia
utilize um disco metálico dentado para efetuar a medida de velocidade angular.
3.7. Comunicação
Para se comunicar com o exterior a placa foi dotada de conexão ICSP para
gravar o programa em C, e uma conexão JTAG utilizada para depuração do
programa e para gravar programas no FPGA. O projeto da placa incorpora
ainda saídas seriais para habilitar comandos e para permitir o monitoramento
remoto por uma outra unidade computacional, como um PC, por exemplo. Essa
conexão remota permitirá ajustar os pontos de operação (set-points) de
operação da roda de reação. Foi criada também uma porta paralela entre o
FPGA e o micro-controlador, para que se possa transmitir dados entre as
unidades de processamento. O circuito de comunicação é apresentado na Fig.
3.13.
USB Debug
Microprocessamento
ICSP/JTAG
RS232/458
I/O’s OU
26
3.8. Fonte de alimentação
R68
(nc)
CN9 3 GS1M-LTP
- + 2 D6 +VCC U13
1 1 4
VIN FEEDBACK R69
11.0183
DC-005 - J4 C63 C64 5 0R +5V
C65 ON-OFF
U14 +3V3
L1
3 2 1
GND VOUT VIN
03.0071 3
R70 VOUT
LM2576D2T 2
100nF
100nF
100nF
100nF
D8
VD
100U F ; 25V
POWER
100U F ; 25V
SK 3 1 0 B - T PC T - N D
27
1 2
1 2
17 16
2 2
1 8
1 1 8
1
1 1
2 7
2 2 2 7
2 1
1
3 6
2
3 6
1 1 1 2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 1 2
2 2 4 5
1 2 4 5
1
1
2
1 2
1 1 1
3
1 2 2 1 2 2 2 1 2
1 2 2 2
1 2 2
1 8
4
2 2 2 1 8
1 1 1
8 7 1 1 1
1 14 2 7 8 7
2 1 2 7
2 1
2 13
9 6
3 6 9 6 1
3 6 1 2 2 1
1 2 2 1
3 12
10 5 1 2 10 5
4 5
1 2 4 5 2
11 4
4 11 11 4
2
3
12 3
5 10 12 3
2
2 2
2 2 2
2
6 9
13 2
13 2
1
3 2
1 8
14 1
1 1 8 1 1 1
7 8 1 1 14 1
2 1
2 1
2 7
2 1
2 7 1
3 6 1 2 2 3 1 6
1 2 2 1
1
1 2
1 2 4 5 1 2
4 5 2 1
3
5
2 1 8 7
2
4 1 2
2 1
9 6
2
2 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1
2 2
10 5 2
1 2 1 2
1
3 2 1 2 1 11 4 1 2
1
2
1
2
1
2 2
1 1 1 1 1 1
12 3
2 2 1 2 2 1 1 2 2 2
13 2
1 14 1
1 1
1
1 2
1 2 1 2
1 2
2 1 1 2
1 8
1 2 1
2 7 1 2
2
3 6 1 2 1
4 5
1 2
2 1 2 1 2 1 2 2
3
1 1
1
1 2 2 1 1 16
2
4
2 2 1 2 2 15
1 2 8 7 6 5
3 14
5
1 2
4 13
1 5 12
6
1
1 2 6 11
1 7 10
2 1
1 2 3 4
2 1 1 2
10 9
8 9
4 1 1 2
8 7
1 2
1 2
1 2
1
1 6 5
1 2 2 1
2 2 1
2 1 2 1
2
2 2 1 1 1 1
4 3 3 2 2 1 1 2
2 1
1
4 3 2 1 2 1
1 2 1 2
2 1 1
1 2
1 2 2 3 2 1 2 1
2 1 2
2 1 1 2
5 6 7 8
2 1 2
2
2
1 2 2 2 1 2 2
1
1
1 2 1 2
2 1
2 1
1
2 1
2 1
3 2 1
1
2 1 1 2
2 1 2 2
1 2 2
2 1
1
1 2 1 2
2
2 1 1
3 6
1
4
2 1
1 2
2
5
4
2 1 2 1
2 1
2 2
1
19 2
2 1
2 1 1
20 17 1
2 1
2 1 2
18 15
2
16 13 2 1
1
14 11 2 1
1 1 2
1
12 9 2 1
1 2
2 1 2
1
10 7 2
2 1 1
2 1
1 2 2
8 5
2 1 1 2 1 2 3
1 2
6 3
1 2
4 1 8 7 6 5
1 1 2 1
2 2 1
2 2 1
2
1 2
1
2 2
1 1 2 2 1
2
1
1
4
3 1 2
6
2
2 1 1 1 2 3 4
1 2 2
5 5 4 3 2 1 1
28
4. PROGRAMA DE CONTROLE DA RODA DE REAÇÃO
29
necessários para o acionamento do circuito, apenas os 3 menos significativos
foram usados, devido ao fato do motor ter apenas 3 fases. Além disso, o bit
menos significativo representa o par de MOSFET 1 e o mais significativo
representa o MOSFET 5.
Para o correto funcionamento do circuito não se deve ter um mesmo bit das
tabelas superior e inferior ligados na mesma posição indexada nas tabelas.
Outro detalhe que deve ser respeitado é a introdução de um atraso entre as
trocas de acionamentos, para acomodar os tempos de resposta dos
transistores MOSFETS (RASHID, 2001). Para os MOSFETS utilizados
(IRF7341) esse tempo foi definido em 100ns, isto é, após uma fase ser
desconectada, será garantido um tempo de 100ms até um novo acionamento
de fase.
30
deseja ter no eixo do motor e a variável de controle é a velocidade medida no
eixo pelos sensores (Hall ou encoders). A saída do controle PID é exatamente
o sinal que será utilizado para atualizar o PWM de acionamento dos mosfet,
que varia de 0 a 100% de ciclo útil. Ou seja, de totalmente desligado a
totalmente ligado.
A leitura dos sinais analógicos é feita por funções de interrupção do timer com
período de 1ms e, após uma média simples de 64 amostras, as medidas são
armazenadas na estrutura de registro do programa.
t
d (4.1)
u (t ) = Kp.e(t ) + Ki ∫ e(t ) dt + Kd e(t )
0 dt
31
P=Kp*(b*ysp-y) "compute proportional part
D=ad*D-bd*(y-yold) "update derivative part
v=P+I+D "compute temporary output
u=sat(v,ulow,uhigh) "simulate actuator saturation
daout(chl) "set analog output chl
I=I+bl*(ysp-y)+a0*(u-v) "update integral
yold=y "update old process output
32
//Header Address Packet ID Data
//0x7F 0xF1 0x40 0x00 0x00 0x7A 0x44
33
void __ISR(_EXTERNAL_1_VECTOR, IPL7) INT1Interrupt( void )
{
if (INTCONbits.INT1EP == 1)
{ executa_sensoreamento_hall( 1 ); }
else
{ executa_sensoreamento_hall( 0 ); }
INTCONbits.INT1EP = ~INTCONbits.INT1EP;// inverte borda de
interrrupção
IFS0bits.INT1IF = 0; // Limpa flag de
interrupção Input Capture 1
}
34
computado mais um acionamento do sensor Hall no cálculo da velocidade de
rotação. O cálculo da velocidade é executado a cada 10 ms, o que resulta em
uma baixa precisão em rotações baixas.
35
Figura 4.1 – Conectores na placa para suporte de encoder de alta resolução.
36
5. Ensaios realizados com o protótipo da roda
37
Figura 5.1 - Ambiente de validação. Software em Labview, conexões seriais e USB e
fonte de alimentação.
38
Essa interface possibilita que seja alterado o alvo para o controlador, seja ele
alvo de corrente ou alvo de rotação, isto é, consegue comandar a roda de
reação para que ela atue na rotação ou corrente que se deseja. Além de
comandar a roda de reação, o software em questão também armazena os
valores de rotação e corrente em um arquivo de texto para posterior análise.
Volante de Inércia
39
5.1. Determinação dos parâmetros de atrito aplicando filtro de Kalman
Para que o filtro de Kalman possa ser aplicado e assim determinar a constante
do motor e os coeficientes de atrito, deve-se coletar um conjunto de dados de
modo que estes dados passem por toda a excursão de velocidades do motor
necessárias para a identificação do sistema. O motor é então comandado com
uma referência em velocidade de rotação com amplitude senoidal por alguns
ciclos completos. Nesse ensaio coletou-se 4 ciclos completos.
Utilizou-se o filtro estendido de Kalman, pois este suporta uma dinâmica não
linear, o que contribuirá para uma melhor estimação dos parâmetros na região
ao redor da velocidade angular nula. Esse filtro é capaz de gerar trajetórias de
referência que são atualizadas a cada processamento das medidas do instante
correspondente (Kuga, 2005).
40
Neste ensaio foram coletadas 6700 amostras em um período de 670 segundos
com 4 ciclos de comando na referência da velocidade angular e amplitude de
4000 rpm. A sintonia do PI foi feita manualmente com ganho proporcional de
500 e ganho integral de 10000, porém o ganho derivativo foi mantido em zero.
Uma roda de reação pode ser modelada por meio de sua inércia Jw, o atrito
viscoso b e um atrito de Coulomb c conforme a seguinte equação diferencial
(Carrara e Milani, 2007):
Tm = k m I , (5.2)
Tm = J w ω
& w + b ωw + c sgn(ωw ) + (s − c) exp(−ωw / ωs ) 2 sgn(ωw ) , (5.3)
41
onde s e ωs[1] são respectivamente o torque de atrito e a velocidade de
Stribeck. Por fim, sob a ótica do experimento tem-se o modelo em termos de
sua entrada I e saída ω:
[
I = Jw ω
& w + b ωw + c sgn(ωw ) + (s − c) exp(−ωw / ωs ) 2 sgn(ωw ) / k m ] (5.4)
y = H k xk + vk , (5.6)
x ≡ [I k ( s − c ) / k m ] ≡ (x1 x5 ) , (5.7)
T T
J w / km b / km c / km x2 x3 x4
uk ≡ (ωk ) , (5.8)
Hk ≡ Iw k( 0 0 0 0 ) (5.9)
1
Fator utilizado para ajuste da atenuação do termo relacionado a s; valores empíricos são atribuídos a ele
(Romano, 2010).
42
O filtro de Kalman selecionado para problema é o tipo estendido, pois este
suporta uma dinâmica não linear, o que certamente contribuirá para se ter uma
melhor estimação dos parâmetros na região ao redor da velocidade angular
nula. Esse filtro é capaz de gerar trajetórias de referência que são atualizadas a
cada processamento das medidas do instante correspondente(Kuga, 2005).
Para aplicação do filtro estendido são geradas as matrizes do jacobiano
referentes às funções não lineares da dinâmica e das medidas.
43
Figura 5.5 - Ganho de Kalman
44
Figura 5.7 –Coeficientes de atrito viscoso
45
senoidal, comandada por um controlador PI embarcado em um micro-
controlador, usado como controlador do motor BLDC.
1500
RPM
1000
500
0
0 5 10 15 20 25 30 35 40 45 t(s)
-500
-1000
-1500
46
5.3. Resposta ao degrau em corrente
300
RPM
250
200
150
100
50
0
0 5 10 15 20 25 30 35 40 45 50 55 60 65t(s)
47
3000
RPM
2500
2000
1500
1000
500
0 t(s)
0 5 10 15 20 25 30 35 40 45 50 55 60 65
48
5.5. Estabilidade em rotação
49
250
RPM
240
230
220
210
200
190
180
170
160
150
t(s)
0 5 10
5000
RPM
4000
3000
2000
1000
0
t(s)
0 50 100 150 200 250 300 350 400 450 500
50
5000
RPM
4000
3000
2000
1000
0
t(s)
0
10
20
30
40
50
60
70
80
90
100
110
120
130
140
150
160
170
180
190
200
210
220
230
240
250
260
270
Figura 5.16 – Resposta ao comando de RPM a 0,011Hz.
Já nas Fig 5.17 e 5.18, nas quais se utilizou uma frequência no sinal de
referência de 0,022 Hz e 0,06 Hz respectivamente, observa-se uma queda
significativa na amplitude da rotação e um atraso entre a referência e a
resposta da roda.
5000
RPM
4000
3000
2000
1000
0
0 10 20 30 40 50 60 70 80 90 100 110 120 130 t(s)
5000
RPM
4000
3000
2000
1000
0
0 5 10 15 20 25 30 35 40 45 t(s)
51
5000
RPM
4000
3000
2000
1000
0
t(s)
0 1 2 3 4 5 6 7 8 9
52
Figura 5.21 – Curva de velocidade do volante de inércia.
Tm = JI (5.10)
O fabricante informa que o motor deve fornecer 14,1 x 10-3 Nm/A, mostrando
desta forma que os valores medidos estão próximos aos valore de produção do
motor. Na Fig. 5.22 é observada a aceleração do volante de inercia ensaiado.
53
Figura 5.22 – Curva de aceleração do volante de inércia.
54
6. CONCLUSÕES
55
• algoritmo de acionamento de fase em onda trapezoidal e senoidal.
• embutir o RTEMS no microcontrolador;
• programar a FPGA com o código do Leon e embutir o RTEMS e leis de
controle nesse microntrolador, já que essa plataforma do LEON em FPGA e
RTEMS deveria ser usada em diversos sensores e atuadores do INPE para
missões;
• projeto mecânico do mancal do volante de inércia;
56
REFERÊNCIAS BIBLIOGRÁFICAS
CARRARA, V.; SIQUEIRA, R.; OLIVEIRA, D.Speed and current mode strategy
comparison in satellite attitude control with reaction wheels. In: BRAZILIAN
CONGRESS OF MECHANICAL ENGINEERING (COBEM), 21., 2011, Natal,
RN, Brazil. Proceedings… Natal: ABCM, 2011.
57
ROMANO, R. A. Identificação de processos não-lineares e quantificação
de atrito em válvulas de controle.Tese (Doutorado em Engenharia de
Sistemas) – Escola Politécnica da Universidade de São Paulo, São Paulo,
Brasil, 2010.
SOUZA, P.N.; FLEURY, A.T. Modelo experimental de uma roda de reação para
controle da atitude de satélites artificiais: construção, simulação e testes. In:
CONGRESSO BRASILEIRO DE ENGENHARIA MECÂNICA, 9., (COBEM),
Florianópolis. Anais... ABCM, 1987. (INPE-4274- PRE/1146).
58
WERTZ, J.R. Spacecraft attitude determination and control. London,
England: D. Reideil Publishing Company, 1978. ISBN:9027709599.
59
60
APÊNDICE A – ESQUEMA ELÉTRICO DO CONTROLADOR
61
62
63
64
65
66
67
68
69
70
APÊNDICE B – Disposição dos componentes
3 2
2 1
3
5
2
4
1
3
1 6
10 9
8 7
6 5
4 3
2 1
19
20 17
2
18 15
16 13
14 11
1
1
12 9
10 7
2
8 5
3
1 2
6 3
4 1
1
2
4
3
6
5 5 4 3 2 1
3 2
2 1
3
5
2
4
1
3
1 6
10 9
8 7
6 5
4 3
2 1
19
20 17
2
18 15
16 13
14 11
1
1
12 9
10 7
2
8 5
3
1 2
6 3
4 1
1
2
4
3
6
5 5 4 3 2 1
71
72
APÊNDICE C – VISTA DA PLACA DO CONTROLADOR
1 2
1 2
2 2 2
1
17
8
16
1 1 8
1
1 1
2 7
2 2 2 1 2 7
1
3 6
2
3 6
1 2
1 1 1 2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
2 2 4 5
1 2
4 5
1
1
1 2
2
2 1
1 1 1
2
3
1 2 2 2 1 2
1 2
1 2 2 2 2
1 8 4
2 2 2 1 8 1
1 1
8 7
1
1 14 1 1 8 7
2 7
2 1 2 7
2 1
2 13
9 6
3 6
9 6 1
3 6 1 2 2 1
1 2 2 1
3 12
10 5 1 2 10 5
4 5
1 2
4 5
2
11 4
4 11 11 4
2
3
12 3
5 10 12 3
2
2
2 2
2 2 2
13 2
6 9 13 2
1
3 2
14 1
1 8
1 1 8
1 1
7 8 1 14 1
1 1
2 1
2 1
2 7
2 1
2 7 1
3 6 1 2 1 2 2 1
2 3 1 6
1
1 2
1 2 1 2
4 5 2 1
4 5
3
5
2 1 8 7
9 6 2
4 1 2
2 1
2
2 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1
2 2
10 5 2
1 2 1 2
2 1
1
3 2 1
11 4 1 2
1
2
1
2
1
2 2
1 1 1 1 1 1
12 3
2 1 2 1
2 2 1 2 2 2
13 2
1 14 1
1 1
1
1 2
1 2 1 2
1 2
2 1 1 2
1 8
1 2 1
2 7
1 2
2
1 2
1
3 6
4 5
2 1
1 2
2
1 2 2
1 2
3
1
1
1
2 1
1 16
2
1 2
4
2
1 2 2 15
2
1 2 3 14
8 7 6 5
1 2
5
4 13
1 5 12
6
1
1 2 6 11
1 2 1 1 2 3 4 7 10
2 1
10 9 2 1
8 9
4 1 1 2
8 7
1 2
1 2
1 2
1
1
6 5
1 2 2 1
2 2 1
2 1 2 1
2
2 2 1 1 1 1
4 3 3 2 2 1 1 2
2 1
1
2 1
4 3 2 1
1 2 1 2 1 2
2 1 1
1 2 2 1 2 1
2 3
1 2
2
2 1 1 2
5 6 7 8
2 1
2
2
1
1
2 2 2 1
2 2
1 2 1 2 1
2 1
2 1
1
2 1
2 1
3 2 1 1
2 1 1 2
2 1 2 2
1
2 2
2 1
1 2
1
1 2
2
2 1
1
3 6
1
4
2 1
1 2 2
5
4
2 1 2 1
2 1
2 2
1
19 2
2 1
2 1 1
20 17 2 1
1
2 1 2
18 15 2
16 13 2 1
1
14 11 2 1
1 1 2
1
12 9 2 1
1 2
2 1 2
1
10 7 2 1
2 1
2 1
1
2
2
8 5
2 1 1 2 1 2 3
1 2
6 3
1 2
4 1 8 7 6 5
1 1 2 1
2 2 1
2 1
2
2
1 2
1
2
2
1 1 2 2 1
2
1
1
4
3 1 2
2
6
2 1 1 1 2 3 4
1 2 2
5 5 4 3 2 1 1
17 16
1
1 1
2 2
1 2
1 1 1 2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
1
1
1 2
2
1 1 1
2
3
2 2
1 2 2 2 2
4
2 2 2 1
1 1
1
1 1
1
1 2 2 1
1 2 2 1
3
2 2
2 2 2 2
3 2
1 1 1 1
1 1
2 1
1 2 1 2 2 1
2 1
1
3
5
2
4 1 2
2 1
1 1
1 1 1
1 2
2 1 1
3 2 1
2
2 2 2
2
2 1 2 1
2 2 2 2
1 1 1
2 1 1 2
1
1 2 3
1 2 2 1 2
4
1
1 2
1 6
1 2
10 9 2 1
8 7 4 1 1
1 2
1
1
6 5
2 1
2 2 1
2
2 1 1 1
4 3 3 2 2 1 1 2
2 1
1 2 1 2 1 2
2 1
1 2
2 1
2
2
2 2 2
1
1
2
2
1 1
1
19
2
20 17 2 1
2
18 15
16 13
14 11 2 1
1
1
12 9 2 1
10 7 2 1
2
8 5
2 1
3
1 2
6 3
4 1
1
2
4
3
6
5 5 4 3 2 1
73
Vista superior 3D da placa de circuito impresso projetada
74
APÊNDICE D – LISTA DE COMPONENTES
75
Resistor 3K24 ; 0,1% 1
Resistor 0R1 1
Microcontrolador PIC PIC32MX675F512H 1
Quad 2-Input AND Gate MM74HCT08M 3
Hex Inverter MM74HCT04M 1
Cyclone II Family EP2C8T144C8N 1
EPCS16 1
Low-Power, RS-485/RS-422 Transceiver MAX485CSA 1
3.0V TO 5.5V, Low-Power,Transceiver MAX3232CSE 1
AT91 ARM Cortex-M4 32-bit
Microcontroller, ATSAM4S16CA-AU 1
Regulador Chaveado Tensão LM2576 1
Regulador de tensão TC1262-3.3 1
1.5 A LDO Regulator LT1963AES8#PBF 1
Amplificador Operacional MCP601 1
Cristal oscilador 8MHz 2
Oscilador 50MHz 1
Cristal oscilador 32KHz 1
76
APÊNDICE E – PROGRAMA DE CONTROLE
/*********************************************************************
*******************\
* Software para controle de motor BLDC
*
*
*
* Desenvolvido por Fernando de Almeida Martins
*
*
*
* E-mail: [email protected]
*
*
*
* Data: 13/02/2012
Versão: 1.0 *
*
*
\*********************************************************************
*******************/
/*********************************************************************
*******************\
* Controle de Versões
*
*
*
* Responsável Versão Data Descrição
*
*
*
* Fernando Martins sw.h 13/02/2012 Rotinas bases
*
* Fernando Martins sw.h 13/05/2015 Sintonia para
protótipo *
*
\*********************************************************************
*******************/
#ifndef _SW_H_
#define _SW_H_
#include "fw.h"
77
/*********************************************************************
*******************\
*******
*********
******* MAPAS DE FLAGS
*********
*******
*********
\*********************************************************************
*******************/
/*********************************************************************
*******************\
* Definição de constantes
*
\*********************************************************************
*******************/
/**************************************************\
* Diretivas de compilação *
\**************************************************/
/**************************************************\
* Flags *
\**************************************************/
/**************************************************\
* Auxiliares *
\**************************************************/
typedef enum {
BLDC_PARALIZADO,
BLDC_ON,
} SM_BLDC;
#define TIMEOUT_BLDC 10
// 10 * 1ms
#define TIMEOUT_PROTOCOLO_AUTOMATICO 100
// 100 * 1ms
// PID:
#define PID_SPEED 0
// Comente esta linha caso não queira utilizar PID para o controle da
bomba BFP
78
#define PID_CURRENT 1
// Comente esta linha caso não queira utilizar PID para o controle da
bomba BFP
#define QTD_MEDIA_RPM 32
#define QTD_MEDIA_CORRENTE 128
/*********************/
#define NUM_PAR_POLOS 4
#define NUM_FASES 3
#define PASSOS_COMUTACAO 6
#define PASSOS_POR_VOLTA
NUM_PAR_POLOS*NUM_FASES*PASSOS_COMUTACAO
#define HALLS_POR_VOLTA
NUM_PAR_POLOS*NUM_FASES*PASSOS_COMUTACAO
/*********************************************************************
*******************\
* Macros
*
\*********************************************************************
*******************/
/*********************************************************************
*******************\
* Definição de estruturas do módulo
*
\*********************************************************************
*******************/
/*********************************************************************
*******************\
* Definição de variáveis do módulo em memória de
programa *
\*********************************************************************
*******************/
// - Globais ao sistema:
79
/*********************************************************************
*******************\
* Definição de variáveis do módulo em memória
de dados *
\*********************************************************************
*******************/
// - Globais ao sistema:
/*********************************************************************
*******************\
* Prototipagem
*
\*********************************************************************
*******************/
/*********************************************************************
*******************\
* Mensagens de error ou warning
*
\*********************************************************************
*******************/
#endif //_SW_H_
80
/*********************************************************************
*******************\
* Software para controle de motor BLDC
*
*
*
* Desenvolvido por Fernando de Almeida Martins
*
*
*
* E-mail: [email protected]
*
*
*
* Data: 13/02/2012
Versão: 1.0 *
*
*
\*********************************************************************
*******************/
/*********************************************************************
*******************\
* Controle de Versões
*
*
*
* Responsável Versão Data Descrição
*
*
*
* Fernando Martins sw.c 13/02/2012 Rotinas bases
*
* Fernando Martins sw.h 13/05/2015 Sintonia para
protótipo *
*
\*********************************************************************
*******************/
#include "sw.h"
/*********************************************************************
*******************\
* Definição de variáveis do software em memória
de programa *
\*********************************************************************
*******************/
// - Globais ao sistema:
/*********************************************************************
*******************\
* Definição de variáveis de flag
*
\*********************************************************************
*******************/
81
union unsigned_char flags_sw1; // Flags de
software
union unsigned_char flags_sw2; // Flags de
software
/*********************************************************************
*******************\
* Definição de variáveis do software em memória
de dados *
\*********************************************************************
*******************/
// - Globais ao software:
// - Globais ao sistema:
/*********************************************************************
*******************\
* Função principal
*
\*********************************************************************
*******************/
inicializa_sw();
#if defined(USB_INTERRUPT)
USBDeviceAttach();
#endif
while( 1 )
{
ClrWdt();
if( F_1MS )
{
F_1MS = 0;
sm_processo_bldc();
}
if( F_10MS )
{
F_10MS = 0;
82
le_fpga_poe_registros();
contador++;
if (contador > 1)
{
contador = 0;
//dados.rpm_alvo = senoide_rpm[ponteiro_alvo++];
if (ponteiro_alvo >= 300)
{
ponteiro_alvo = 0;
}
}
}
if( F_PORTA_SERIAL_PCT_RX )
{
trata_pct_serial_rx();
F_PORTA_SERIAL_PCT_RX = 0;
}
return( 0 );
}
/*********************************************************************
*******************\
* Implementação das funções
*
\*********************************************************************
*******************/
buffer_rpm[ponteiro++] = dados.contador_hall;
dados.contador_hall = 0;
if (ponteiro >= 30)
{
ponteiro = 0;
}
aux = 0;
for ( i = 0 ; i < 30 ; i++)
{
aux += buffer_rpm[i];
}
if (dados.sentido_rotacao_real == SENTIDO_HORARIO)
{
dados.rpm_real = aux * 10;
}
else
{
83
dados.rpm_real = -aux * 10;
}
}
/*********************************************************************
*******************\
* sm_processo_bldc
*
* Máquina de estado para controle do tempo e armazenamento
*
*
*
* Parâmetros: void
*
* Retorno : void
*
\*********************************************************************
*******************/
inline void sm_processo_bldc( void )
{
static unsigned int esforco;
static unsigned int ponteiro;
static unsigned int timeout = TIMEOUT_BLDC;
static unsigned int timeout2 = TIMEOUT_PROTOCOLO_AUTOMATICO;
static unsigned char buffer_final[ 17 ];// 1 caracter para sinal,
1 caracter para ponto decimal e outro para o fim da string
unsigned char i;
switch (sm_bldc)
{
case BLDC_PARALIZADO:
ponteiro = 0;
dados.pwm = 0;
inicia_pid_controle( PID_SPEED );
inicia_pid_controle( PID_CURRENT );
// DEBUG finaliza_pid_controle( PID_SPEED );
// DEBUG finaliza_pid_controle( PID_CURRENT );
if (dados.parametros.on == ON)
{
sm_bldc = BLDC_ON;
}
break;
case BLDC_ON:
timeout --;
if (timeout == 0)
{
timeout = TIMEOUT_BLDC;
calcula_rpm();
calcula_rpm_medio();
calcula_corrente_media();
if ( dados.tipo_controle == PID_SPEED )
{
if (dados.rpm_real_medio >= 0)
{
dados.sentido_rotacao = SENTIDO_HORARIO;
84
esforco = (algoritmo_pid_controle( PID_SPEED,
dados.rpm_alvo + 10000, dados.rpm_real + 10000 )); // delta de 20000
para aceitar rotações negativas
}
else
{
dados.sentido_rotacao = SENTIDO_ANTI_HORARIO;
esforco = (algoritmo_pid_controle(
PID_SPEED,dados.rpm_real + 10000, dados.rpm_alvo + 10000));
}
}
else
{
if (dados.corrente_real_media >= 0)
{
dados.sentido_rotacao = SENTIDO_HORARIO;
esforco = (algoritmo_pid_controle(
PID_CURRENT, dados.corrente_alvo + 10000, dados.corrente_real_media +
10000 ));
}
else
{
dados.sentido_rotacao = SENTIDO_ANTI_HORARIO;
esforco = (algoritmo_pid_controle(
PID_CURRENT, dados.corrente_real_media + 10000, dados.corrente_alvo +
10000 ));
}
}
if (dados.parametros.on == OFF)
{
sm_bldc = BLDC_PARALIZADO;
}
timeout2 --;
if (timeout2 == 0)
{
timeout2 = TIMEOUT_PROTOCOLO_AUTOMATICO;
if ( dados.tipo_protocolo == SIMPLIFICADO)
{
envia_resposta(ID_WR_SPEED_MEASURED,
dados.rpm_real_medio);
envia_resposta(ID_WR_CURRENT_MEASURED,
dados.corrente_real_media);
}
}
break;
}
}
85
void calcula_rpm_medio( void )
{
static signed long acc[QTD_MEDIA_RPM];
static unsigned char inicio = 1;
static unsigned char ponteiro = 0;
signed long aux;
unsigned char i;
if (inicio)
{
inicio = 0;
ponteiro = 0;
for (i = 0; i < QTD_MEDIA_RPM; i++)
{
acc[QTD_MEDIA_RPM] = 0;
}
}
acc[ponteiro++] = dados.rpm_real;
aux = 0;
if (inicio)
{
inicio = 0;
ponteiro = 0;
for (i = 0; i < QTD_MEDIA_CORRENTE; i++)
{
acc[QTD_MEDIA_CORRENTE] = 0;
}
}
acc[ponteiro++] = adc.ifase;
86
ponteiro = 0;
}
aux = 0;
if ((dados.sentido_rotacao_real == SENTIDO_ANTI_HORARIO) ||
(dados.freio == 1))
{
dados.corrente_real_media = -aux / (QTD_MEDIA_CORRENTE/8);
}
else
{
dados.corrente_real_media = aux / (QTD_MEDIA_CORRENTE/8);
}
}
/*********************************************************************
*******************\
* inicializa_sw
*
* Rotina de inicialização do software
*
*
*
* Parâmetros: void
*
* Retorno : void
*
\*********************************************************************
*******************/
void inicializa_sw( void )
{
unsigned char i;
inicializa_fw();
// Zera flags
flags_sw1.value = 0;
flags_sw2.value = 0;
//inicializa_memoria_dados_eeprom();;
87
controle.pid[ PID_SPEED ].TT = PID_SPEED_TT; // Tempo de
tracking para o anti-windup
controle.pid[ PID_SPEED ].bp = PID_SPEED_KP; // Banda
proporcional
controle.pid[ PID_SPEED ].ti = PID_SPEED_KI; // Tempo
integral
controle.pid[ PID_SPEED ].td = PID_SPEED_KD; // Tempo
derivativo
#endif
dados.pwm = 0;
dados.rpm_alvo = 0;
dados.rpm_real = 0;
dados.corrente_alvo = 0;
dados.corrente_real_media = 0;
dados.tipo_controle = PID_SPEED;
dados.tipo_protocolo = SIMPLIFICADO;
dados.parametros.on = ON;
dados.sentido_rotacao = SENTIDO_HORARIO;
}
/*********************************************************************
*******************\
* time_out
*
* Rotina para contar e indicaqr quanto o tempo estourar
*
*
*
* Parâmetros: tempo inicial
*
* Retorno : 0 tempo estourado, >0 contagem em andamento , -1 já
acabou *
\*********************************************************************
*******************/
unsigned int time_out ( unsigned char inicia, unsigned int
tempo_inicial)
{
88
static unsigned int tempo = 0;
if (inicia)
{
tempo = tempo_inicial;
}
else
{
if (tempo) // maior que 0?
{
tempo--;
return(tempo); // se zero , acabou
}
else // ja indicou estouro , agora é erro
{
return(-1);
}
}
return(2); // em andamento
}
89
/*********************************************************************
*******************\
* Software para controle de motor BLDC
*
*
*
* Desenvolvido por Fernando de Almeida Martins
*
*
*
* E-mail: [email protected]
*
*
*
* Data: 15/04/2014
Versão: 1.0 *
*
*
\*********************************************************************
*******************/
/*********************************************************************
*******************\
* Controle de Versões
*
*
*
* Responsável Versão Data Descrição
*
*
*
* Fernando Martins protocolo.h 15/04/2014 Rotinas
bases *
*
*
*
*
\*********************************************************************
*******************/
#ifndef PROTOCOLO_SERIAL_H
#define PROTOCOLO_SERIAL_H
/*********************************************************************
*******************\
*******
*********
******* MAPAS DE FLAGS
*********
*******
*********
\*********************************************************************
*******************/
90
/*****
* bit0: F_PROTOCOLO_RESERVADO
****/
/*********************************************************************
*******************\
* Definição de variáveis do firmware em memória
de programa *
\*********************************************************************
*******************/
/*********************************************************************
*******************\
* Definição de constantes
*
\*********************************************************************
*******************/
91
//#define ID_K2_GAIN_INERTIAL_RATE 0x45 //Gain K2 for
inertial rate PI controller
#define ID_K1_GAIN_SPEED 0x47 //Gain K1 for
wheel speed PI controller
#define ID_K2_GAIN_SPEED 0x48 //Gain K2 for
wheel speed PI controller
//#define ID_K1_GAIN_INERTIAL_ANGLE 0x49 //Gain K1 for
inertial delta angle P controller
#define ID_RW_GYRO_ON_OFF 0x4A //RW & Gyro
ON/OFF switch*
//#define ID_GYRO_OFFSET_BIAS 0x4B //Gyro offset
(bias) correction
/**************************************************\
* Diretivas de compilação *
\**************************************************/
/**************************************************\
* Flags *
\**************************************************/
/**************************************************\
* constantes e estruturas *
\**************************************************/
/*********************************************************************
*******************\
* Definição de variáveis do módulo em memória de
programa *
\*********************************************************************
*******************/
// - Globais ao sistema:
// - Globais ao módulo:
/*********************************************************************
*******************\
* Definição de variáveis do módulo em memória
de dados *
\*********************************************************************
*******************/
// - Globais ao sistema:
// - Globais ao módulo:
/*********************************************************************
*******************\
92
* Macros
*
\*********************************************************************
*******************/
/*********************************************************************
*******************\
* Prototipagem
*
\*********************************************************************
*******************/
inline void trata_pct_serial_rx( void );
void trata_protocolo_serial(void);
void envia_resposta_curta( unsigned char id );
void envia_resposta( unsigned char id, signed long data );
/****************************************************************\
* Funções do módulo
*
\****************************************************************/
#endif /* PROTOCOLO_SERIAL_H */
93
/*********************************************************************
*******************\
* Software para controle de motor BLDC
*
*
*
* Desenvolvido por Fernando de Almeida Martins
*
*
*
* E-mail: [email protected]
*
*
*
* Data: 15/04/2014
Versão: 1.0 *
*
*
\*********************************************************************
*******************/
/*********************************************************************
*******************\
* Controle de Versões
*
*
*
* Responsável Versão Data Descrição
*
*
*
* Fernando Martins protocolo.h 15/04/2014 Rotinas
bases *
*
*
*
*
\*********************************************************************
*******************/
#include "protocolo_serial.h"
/*********************************************************************
*******************\
* Flags do módulo
*
\*********************************************************************
*******************/
/*********************************************************************
*******************\
* Definição de variáveis do módulo em memória de
programa *
94
\*********************************************************************
*******************/
// - Globais ao módulo:
// - Globais ao sistema:
/*********************************************************************
*******************\
* Definição de variáveis do módulo em memória
de dados *
\*********************************************************************
*******************/
// - Globais ao módulo:
typedef union {
long llong;
float ffloat;
} Unionlonttofloat;
// - Globais ao sistema:
/*********************************************************************
*******************\
* Funções estáticas
*
\*********************************************************************
*******************/
/*********************************************************************
*******************\
* Vetores de interrupção
*
\*********************************************************************
*******************/
/*********************************************************************
*******************\
* Implementação das funções
*
\*********************************************************************
*******************/
/*********************************************************************
*******************\
*
*
95
* Rotina para iniciar o protocolo
*
*
*
* Parâmetros: void
*
* Retorno : void
*
\*********************************************************************
*******************/
// Data packet
//The data packet structure is used for
//Telemetry responses (Packet ID = 0x10 to 0x3F) that originate in the
slave node
//Telecommands (Packet ID = 0x40 to 0x6F) that originate in the master
node
//
//Telecommand: Command the x-axis reaction wheel to go to 1000 rpm.
//The master node, or desktop computer, transmits the wheel speed
telecommand
//(packet ID 0x40) to the slave node, or x-axis of the reaction wheel
and gyroscope electronics,
//(address 0xF1) with the telecommand data set to the 32-bit floating
point representation for a value of 1000:
//Header Address Packet ID Data
//0x7F 0xF1 0x40 0x00 0x00 0x7A 0x44
//
//The slave node, or x-axis of the reaction wheel and gyroscope
electronics, (address 0xF1) responds with a wheel
//telecommand acknowledge (packet ID 0x40) within 20 milliseconds:
//Header Node address Packet ID
//0x7F 0xF1 0x40
//
96
//Telemetry packet ID:
//0x10 RW speed measured by shaft encoder (rpm)
//0x11 RW motor current measured (mA)
//0x12
//0x13 Gyro accumulated measurement
//0x14 Gyro raw measurement
//0x15 Status
//0x16
//0x17 Controller temperature (°C)
//0x18 Software version
//0x19 RW temperature (°C)
//0x1A RW pressure (psi)
//0x1B Inertial delta angle telemetry (°)
// protocolo adicional INPE
//0x1C request speed reference (rpm)
//0x1D request current reference (mA)
//
//Telecommand packet ID:
//0x40 RW speed control ON & speed reference (rpm)
//0x41 RW current control ON & current reference (mA)
//0x42 Inertial rate control ON & rate reference (°/s)
//0x43 Inertial ? angle control ON & angle reference (°)
//0x44 Gain K1 for inertial rate PI controller
//0x45 Gain K2 for inertial rate PI controller
//0x46
//0x47 Gain K1 for wheel speed PI controller
//0x48 Gain K2 for wheel speed PI controller
//0x49 Gain K1 for inertial delta angle P controller
//0x4A RW & Gyro ON/OFF switch*
//0x4B Gyro offset (bias) correction
97
//since the dynamic friction of the reaction wheel decreases the
effective wheel
//torque at higher wheel speeds.)
//The value of the current reference must be between ?2200 and +2200
mA. The master node may
//transmit current reference telecommands to the slave node at a
maximum rate of 10 Hz
//(sampling time = 100 ms).
//8.2 Speed control mode
//
//When the master node transmits a speed reference telecommand (packet
ID 0x40),
//the speed control mode is selected and the slave node controls the
reaction
//wheel speed to follow the reference speed. The speed control mode is
useful
//since the torque applied to the spacecraft body can be controlled
more accurately
//by commanding the wheel speed to track a reference wheel speed
profile. Accurate wheel
//speed control is also equivalent to accurate wheel momentum control.
//The wheel speed controller is a PI controller with a sampling time
of Ts = 100ms.
//The master node can set the wheel speed controller gains and by
transmitting their corresponding
//telecommands (packet ID 0x47 and 0x48 respectively). However, it
should not be necessary to change
//the wheel speed controller gains under normal circumstances, since
the optimal default gains have
//already been chosen for the specific reaction wheel. The default
gains for the wheel speed
//controller are and . k1=2000 e k2 = -1900
//The value of the speed reference must be between ?4200 and +4200
rpm. The master node may
//transmit speed reference telecommands to the slave node at a maximum
rate of 1 Hz
//(sampling time = 1 second).
/*
MUDA SPEED 1000RPM
7F F1 40 00 00 7A 44
SPEED -1000RPM
7F F1 40 00 00 7A C4
CORRENTE 100MA
7F F1 41 00 00 C8 42
CORRENTE 200MA
7F F1 41 00 00 48 43
REQUEST SPEED
7F F1 10
REQUEST CURRENT
98
7F F1 11
*/
/*********************************************************************
*******************\
* trata_pct_serial_rx
*
* Rotina para tratamento do pacote serial recebido. Os pacotes
recebidos aqui referem- *
* se aos dados enviados pelo leitor de código de barras
*
*
*
* Parâmetros: void
*
* Retorno : void
*
\*********************************************************************
*******************/
inline void trata_pct_serial_rx( void )
{
if (( uart_1.rx[ 0 ] == HEADER) && ( uart_1.rx[ 1 ] ==
NODE_ADDRESS) )
{
trata_protocolo_serial();
dados.tipo_protocolo = SUNSPACE; // a partir de então começo a
trabalhar no protocolo sunspace
}
uart_1.tam_rx = 0;
}
void trata_protocolo_serial(void)
{
union unsigned_char aux;
static unsigned char buffer_serial[5];
Unionlonttofloat longtofloat;
buffer_serial[0] = uart_1.rx[ 2 ];
buffer_serial[1] = uart_1.rx[ 3 ];
buffer_serial[2] = uart_1.rx[ 4 ];
buffer_serial[3] = uart_1.rx[ 5 ];
buffer_serial[4] = uart_1.rx[ 6 ];
uart_1.tam_rx = 0;
switch (buffer_serial[0])
{
case ID_WR_SPEED_MEASURED: //RW speed
measured by shaft encoder (rpm)
envia_resposta(ID_WR_SPEED_MEASURED,
dados.rpm_real_medio);
break;
99
aux.value = 0;
aux.bit1 = (dados.parametros.on? 1 : 0); //
Bit 1: RW On.
aux.bit4 = (dados.tipo_controle? 0 : 1); //
Bit 4: Current loop active.
aux.bit5 = (dados.tipo_controle? 1 : 0); //
Bit 5: Speed loop active.
envia_resposta(ID_STATUS, aux.value );
break;
100
break;
default:
break;
tam_pacote_atual = porta_serial.tam_tx;
longtofloat.ffloat = data;
porta_serial.tx[tam_pacote_atual] = HEADER;
porta_serial.tx[tam_pacote_atual + 1] = NODE_ADDRESS;
porta_serial.tx[tam_pacote_atual + 2] = id;
porta_serial.tx[tam_pacote_atual + 3] = longtofloat.llong;
porta_serial.tx[tam_pacote_atual + 4] = longtofloat.llong >> 8;
porta_serial.tx[tam_pacote_atual + 5] = longtofloat.llong >> 16;
porta_serial.tx[tam_pacote_atual + 6] = longtofloat.llong >> 24;
porta_serial.tam_tx = tam_pacote_atual + 7;
tx_pacote_porta_serial();
}
/*************************************************/
/*************************************************/
/*************************************************/
101
/*********************************************************************
*******************\
* Módulo Controle
*
\*********************************************************************
*******************/
#ifndef _CONTROLE_H_
#define _CONTROLE_H_
#define MOD_CONTROLE
/*********************************************************************
*******************\
*******
*********
******* MAPAS DE FLAGS
*********
*******
*********
\*********************************************************************
*******************/
/********************************************\
* Flags: *
\********************************************/
/********************************************\
* Auxiliares: *
\********************************************/
/*********************************************************************
*******************\
102
* Definição de estruturas do módulo
*
\*********************************************************************
*******************/
typedef struct
{
struct
{
unsigned char on : 1;
float N;
float H;
float TT;
float bp; // x 10
float ti;
float td;
} pid[ CONTROLE_TOTAL_PID ];
struct
{
unsigned char on : 1;
unsigned char acao : 1;
int histerese; // x 10
} onoff[ CONTROLE_TOTAL_ONOFF ];
} Controle;
/*********************************************************************
*******************\
* Definição de variáveis do módulo em memória de
programa *
\*********************************************************************
*******************/
// - Globais ao sistema:
/*********************************************************************
*******************\
* Definição de variáveis do módulo em memória
de dados *
\*********************************************************************
*******************/
// - Globais ao sistema:
extern Controle controle;
/*********************************************************************
*******************\
* Macros
*
\*********************************************************************
*******************/
103
/*********************************************************************
*******************\
* Prototipagem
*
\*********************************************************************
*******************/
#endif // _CONTROLE_H_
104
/*********************************************************************
*******************\
* Módulo Controle
*
*
*
\*********************************************************************
*******************/
/*********************************************************************
*******************\
* Flags do módulo
*
\*********************************************************************
*******************/
/*********************************************************************
*******************\
* Definição de variáveis do módulo em memória de
programa *
\*********************************************************************
*******************/
// - Globais ao módulo:
// - Globais ao sistema:
/*********************************************************************
*******************\
* Definição de variáveis do módulo em memória
de dados *
\*********************************************************************
*******************/
// - Globais ao módulo:
struct
{
unsigned char estado : 1; // Estado: ON/OFF
unsigned char inicio : 1; // Início do controle
struct
{
unsigned char estado : 1; // Estado: ON/OFF
unsigned char inicio : 1; // Início do controle
105
float bd; // Termo bd
float bi; // Termo bi
float bt; // Termo bt
float d_ant; // d(n-1)
float y_ant; // pv(n-1)
float u; // Esforço de controle
com saturação (0..100%)
float v; // Esforço de controle
sem saturação
float p_n; // Termo proporcional
float i_n; // Termo integral
float d_n; // Termo derivativo
} pid[ CONTROLE_TOTAL_PID ];
// - Globais ao sistema:
Controle controle;
/*********************************************************************
*******************\
* Funções estáticas
*
\*********************************************************************
*******************/
/*********************************************************************
*******************\
* Vetores de interrupção
*
\*********************************************************************
*******************/
/*********************************************************************
*******************\
* Implementação das funções
*
\*********************************************************************
*******************/
/*********************************************************************
*******************\
* inicializa_controle
*
* Rotina para iniciar o módulo Controle
*
*
*
* Parâmetros: void
*
* Retorno : void
*
\*********************************************************************
*******************/
106
void inicializa_controle( void )
{
unsigned char i;
// Zera variáveis
for( i = 0 ; i < CONTROLE_TOTAL_ONOFF ; i++ )
{
onoff[ i ].estado = OFF;
onoff[ i ].inicio = 1;
onoff[ i ].saida = 0;
controle.onoff[ i ].on = 0;
controle.onoff[ i ].acao = ONOFF_ACAO_NORMAL;
}
controle.pid[ i ].on = 0;
}
}
/*********************************************************************
***********\
* inicia_pid_controle
*
* Rotina de liberação do algoritmo de PID
*
*
*
* Parâmetros: índice do controlador PID
*
* Retorno: void
*
\*********************************************************************
***********/
void inicia_pid_controle( unsigned char n )
{
controle.pid[ n ].on = 1;
107
/*********************************************************************
***********\
* finaliza_pid_controle
*
* Rotina de finalização do algoritmo de PID
*
*
*
* Parâmetros: índice do controlador PID
*
* Retorno: void
*
\*********************************************************************
***********/
inline void finaliza_pid_controle( unsigned char n )
{
controle.pid[ n ].on = 0;
/*********************************************************************
***********\
* algoritmo_pid_controle
*
* Rotina de execução do algoritmo de controle PID
*
*
*
* Parâmetros: índice do controlador PID, set-point e variável de
controle (em *
* ponto flutuante)
*
* Retorno: esforço do controle, de 0 a 1000
*
\*********************************************************************
***********/
unsigned int algoritmo_pid_controle( unsigned char n, float sp, float
y )
{
if( pid[ n ].estado == ON )
{
// Cálculo do termo ad
pid[ n ].ad = controle.pid[ n ].td / ( controle.pid[ n ].td +
( controle.pid[ n ].N * controle.pid[ n ].H ) );
// Cálculo do termo bd
pid[ n ].bd = ( 100.0 / controle.pid[ n ].bp ) *
controle.pid[ n ].N * pid[ n ].ad;
108
}
else
{
pid[ n ].bi = ( ( 100.0 / controle.pid[ n ].bp ) *
controle.pid[ n ].H ) / controle.pid[ n ].ti;
pid[ n ].bt = controle.pid[ n ].H / controle.pid[ n ].TT;
}
// i(n+1)
pid[ n ].i_n = ( pid[ n ].bi * ( sp - y ) ) + ( pid[ n ].bt *
( pid[ n ].u - pid[ n ].v ) ) + pid[ n ].i_n;
return( 0 );
}
109
/*********************************************************************
***********\
* inicia_onoff_controle
*
* Rotina de liberação do algoritmo de ONOFF
*
*
*
* Parâmetros: índice do controlador ONOFF
*
* Retorno: void
*
\*********************************************************************
***********/
void inicia_onoff_controle( unsigned char n )
{
controle.onoff[ n ].on = 1;
onoff[ n ].saida = 0;
}
/*********************************************************************
***********\
* finaliza_onoff_controle
*
* Rotina de finalização do algoritmo de ONOFF
*
*
*
* Parâmetros: índice do controlador ONOFF
*
* Retorno: void
*
\*********************************************************************
***********/
inline void finaliza_onoff_controle( unsigned char n )
{
controle.onoff[ n ].on = 0;
/*********************************************************************
***********\
* algoritmo_onoff_controle
*
* Rotina de execução do algoritmo de controle ONOFF
*
*
*
* Parâmetros: índice do controlador ONOFF, set-point e variável de
controle (em*
110
* ponto flutuante)
*
* Retorno: esforço do controle, de 0 a 1000
*
\*********************************************************************
***********/
unsigned int algoritmo_onoff_controle( unsigned char n, float sp,
float pv )
{
int histerese;
return( 0 );
}
111
/*********************************************************************
*******************\
* Módulo Capture
*
*
*
*
*
\*********************************************************************
*******************/
/*********************************************************************
*******************\
* Flags do módulo
*
\*********************************************************************
*******************/
/*********************************************************************
*******************\
* Definição de variáveis do módulo em memória de
programa *
\*********************************************************************
*******************/
// - Globais ao módulo:
// - Globais ao sistema:
/*********************************************************************
*******************\
* Definição de variáveis do módulo em memória
de dados *
\*********************************************************************
*******************/
// - Globais ao módulo:
// - Globais ao sistema:
/*********************************************************************
*******************\
* Funções estáticas
*
\*********************************************************************
*******************/
112
/*********************************************************************
*******************\
* Vetores de interrupção
*
\*********************************************************************
*******************/
void __ISR(_EXTERNAL_1_VECTOR, IPL7) INT1Interrupt( void )
{
if (INTCONbits.INT1EP == 1)
{
executa_sensoreamento_hall( 1 );
}
else
{
executa_sensoreamento_hall( 0 );
}
INTCONbits.INT1EP = ~INTCONbits.INT1EP;
IFS0bits.INT1IF = 0; // Limpa
flag de interrupção Input Capture 1
}
/*********************************************************************
*******************\
* Implementação das funções
*
\*********************************************************************
*******************/
/*********************************************************************
*******************\
* inicializa_captures
*
* Rotina de inicialização do módulo Input Capture
*
*
*
* Parâmetros: void
*
113
* Retorno: void
*
\*********************************************************************
*******************/
void inicializa_captures( void )
{
INTCON = 0x000E;
IPC1bits.INT1IP = 7;
IPC2bits.INT2IP = 7;
IPC3bits.INT3IP = 7;
IFS0bits.INT1IF = 0;
IFS0bits.INT2IF = 0;
IFS0bits.INT3IF = 0;
IEC0bits.INT1IE = 1;
IEC0bits.INT2IE = 1;
IEC0bits.INT3IE = 1;
114
/*********************************************************************
*******************\
* Módulo Timer
*
*
*
*
*
*
*
\*********************************************************************
*******************/
/*********************************************************************
*******************\
* Flags do módulo
*
\*********************************************************************
*******************/
/*********************************************************************
*******************\
* Definição de variáveis do módulo em memória de
programa *
\*********************************************************************
*******************/
// - Globais ao módulo:
// - Globais ao sistema:
/*********************************************************************
*******************\
* Definição de variáveis do módulo em memória
de dados *
\*********************************************************************
*******************/
// - Globais ao módulo:
unsigned char tempo_10ms; // Contador para
base de tempo de 10ms
unsigned char tempo_50ms; // Contador para
base de tempo de 50ms
unsigned char tempo_100ms; // Contador para
base de tempo de 100ms
unsigned char tempo_500ms; // Contador para
base de tempo de 500ms
unsigned char tempo_1000ms; // Contador para
base de tempo de 1000ms
// - Globais ao sistema:
115
/*********************************************************************
*******************\
* Timer2 Interrupt Service Routine - 1ms
*
*
*
* Descrição: Base de tempo de 1ms
*
* Prioridade: 2 (baixa)
*
\*********************************************************************
*******************/
void __ISR(_TIMER_2_VECTOR, IPL4) _T2Interrupt( void )
{
calcula_base_tempo(); // Gera as bases
de tempo
/*********************************************************************
*******************\
* Timer2 Interrupt Service Routine - 1mS
*
*
*
* Descrição: Base de tempo de 1mS
*
* Prioridade: 7 ( máxima)
*
\*********************************************************************
*******************/
void __ISR(_TIMER_3_VECTOR, IPL6) _T3Interrupt( void )
{
IFS0bits.T3IF = 0; // Limpa flag de
interrupção Timer2
/*********************************************************************
*******************\
* Timer2 Interrupt Service Routine - 1mS
*
*
*
* Descrição: Base de tempo de 1mS
*
* Prioridade: 7 ( máxima)
*
\*********************************************************************
*******************/
void __ISR(_TIMER_4_VECTOR, IPL4) _T4Interrupt( void )
{
static unsigned long contador_anterior;
116
LED2 = ~LED2;
if (contador_anterior == dados.contador_hall)
{
if ((dados.rpm_alvo != 0) || (dados.corrente_alvo != 0))
{
atualiza_rpm ( 0 );
}
}
contador_anterior = dados.contador_hall;
}
/*********************************************************************
*******************\
* Implementação das funções
*
\*********************************************************************
*******************/
/*********************************************************************
*******************\
* inicializa_timer
*
* Rotina de inicialização do Timer2
*
*
*
* Parâmetros: void
*
* Retorno : void
*
\*********************************************************************
*******************/
inline void inicializa_timer( void )
{
flags_timer.value = 0; // Zera flags do
módulo Timer
117
PR2 = VALOR_TMR2; // Carrega período
do Timer2
IPC2bits.T2IP = 4; // Nível de
prioridade: 6 (quase máxima)
IFS0bits.T2IF = 0; // Limpa flag de
interrupção do Timer2
IEC0bits.T2IE = 1; // Habilita
interrupção Timer2
T2CONbits.TON = 1; // Liga Timer2
/*********************************************************************
*******************\
* calcula_base_tempo
*
* Rotina para cálculo das bases de tempo do sistema
*
*
*
* Parâmetros: void
*
* Retorno : void
*
\*********************************************************************
*******************/
void calcula_base_tempo( void )
{
F_1MS = 1; // Informa que
passou-se 1ms
118
trata_uart(); // Envio de
pacotes de dados pela serial e teste de timeouts de transmissão e
recepção
tempo_10ms--; // Decrementa
tempo da base de 10ms
if( !tempo_10ms ) // Fim do tempo?
Sim
{
F_10MS = 1; // Informa que
passou-se 10ms
tempo_10ms = T_10MS; // Recarrega tempo
tempo_50ms--; // Decrementa
tempo da base de 50ms
if( !tempo_50ms ) // Fim do tempo?
Sim
{
F_50MS = 1; // Informa que
passou-se 50ms
tempo_50ms = T_50MS; // Recarrega tempo
tempo_100ms--; // Decrementa
tempo da base de 100ms
if( !tempo_100ms ) // Fim do tempo?
Sim
{
F_100MS = 1; // Informa que
passou-se 100ms
tempo_100ms = T_100MS; // Recarrega tempo
tempo_500ms--; // Decrementa
tempo da base de 500ms
if( !tempo_500ms ) // Fim do tempo?
Sim
{
F_500MS = 1; // Informa que
passou-se 500ms
tempo_500ms = T_500MS; // Recarrega tempo
tempo_1000ms--; // Decrementa
tempo da base de 1000ms
if( !tempo_1000ms ) // Fim do tempo?
Sim
{
F_1000MS = 1; // Informa que
passou-se 1000ms
tempo_1000ms = T_1000MS; // Recarrega tempo
}
}
}
}
}
}
119