Controle de Trim Tab para FlightGear com Arduino Nano: Roda Analógica Compacta
Componentes e Materiais
| Componente | Quantidade | Observações |
|---|---|---|
| Arduino Nano R3 (ou compatível) | 1 | |
| Potenciômetro rotativo (10kΩ recomendado) | 1 | Eixo para knob de trim |
| Capacitor 100µF | 1 | Filtro de ruído no potenciômetro |
| Display OLED SSD1306 0.96" I2C (128x64) | 1 | Feedback visual da posição |
| Fios jumpers | 1 conjunto |
Software Necessário
- Arduino IDE
- Python 3 com bibliotecas:
pyserial,socket,sys(instale viaconda install -c anaconda pyserialoupip install pyserial) - FlightGear (simulador de voo open-source)
- Biblioteca Arduino: U8glib (para display OLED)
Sobre o Projeto
Este projeto cria uma roda de trim (trim wheel) analógica física para controlar o trim do elevador no simulador FlightGear. O Arduino lê o potenciômetro e envia dados via Serial; um script Python converte para pacotes UDP que o FlightGear entende via protocolo genérico.
O que é Trim Tab?
O trim tab é uma pequena superfície de controle na borda do estabilizador horizontal (elevador) que permite manter o avião em atitude de voo nivelada sem pressão constante no manche. A roda de trim no cockpit ajusta essa superfície.
Arquitetura do Sistema
[Potenciômetro] → [Arduino Nano (Serial USB)] → [Python Script (UDP)] → [FlightGear (Generic Protocol)]
Três arquivos de código:
- arduinoElevatorTrimOLED.ino – Sketch do Arduino (carregar na placa)
- arduinoElevatorTrim.py – Script Python (executar junto com FlightGear)
- arduinoElevatorTrim.xml – Protocolo genérico do FlightGear (copiar para
<FlightGearRoot>/data/protocol/)
Código do Arduino (arduinoElevatorTrimOLED.ino)
#include <U8glib.h>
// Ajuste linha 2 para seu display:
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE | U8G_I2C_OPT_DEV_0); // I2C/TWI
int xmax = 128, ymax = 64;
int xcenter = xmax/2, ycenter = ymax/2 + 10;
int arc = ymax/2;
int angle = 0;
char* label = "TRIM";
int labelXpos = 53;
int p, w, m;
u8g_uint_t xx = 0;
const int potPin = A6;
float potVal;
void gauge(uint8_t angle) {
// Desenha borda do medidor (arco superior)
u8g.drawCircle(xcenter, ycenter, arc+6, U8G_DRAW_UPPER_RIGHT);
u8g.drawCircle(xcenter, ycenter, arc+4, U8G_DRAW_UPPER_RIGHT);
u8g.drawCircle(xcenter, ycenter, arc+6, U8G_DRAW_UPPER_LEFT);
u8g.drawCircle(xcenter, ycenter, arc+4, U8G_DRAW_UPPER_LEFT);
// Desenha agulha
float x1 = sin(2*angle*2*3.14/360);
float y1 = cos(2*angle*2*3.14/360);
u8g.drawLine(xcenter, ycenter, xcenter+arc*x1, ycenter-arc*y1);
u8g.drawDisc(xcenter, ycenter, 5, U8G_DRAW_UPPER_LEFT);
u8g.drawDisc(xcenter, ycenter, 5, U8G_DRAW_UPPER_RIGHT);
// Labels da escala
u8g.setFont(u8g_font_chikita);
u8g.drawStr(1, 42, "DOWN");
u8g.drawStr(52, 17, "NEUT");
u8g.drawStr(105, 42, "UP");
// Label "TRIM"
u8g.setPrintPos(labelXpos, 32);
u8g.print(label);
// Valor digital alinhado
u8g.setFont(u8g_font_profont22);
if (w >= 99) u8g.setPrintPos(47, 60);
else if (w >= 10) u8g.setPrintPos(54, 60);
else if (w >= 0) u8g.setPrintPos(60, 60);
else if (w >= -9) u8g.setPrintPos(48, 60);
else if (w >= -99) u8g.setPrintPos(42, 60);
else u8g.setPrintPos(35, 60);
u8g.print(w);
}
void setup() {
Serial.begin(9600);
u8g.setFont(u8g_font_chikita);
u8g.setColorIndex(1);
// Configuração de cor para diferentes modos de display
if (u8g.getMode() == U8G_MODE_R3G3B2) u8g.setColorIndex(255);
else if (u8g.getMode() == U8G_MODE_GRAY2BIT) u8g.setColorIndex(3);
else if (u8g.getMode() == U8G_MODE_BW) u8g.setColorIndex(1);
else if (u8g.getMode() == U8G_MODE_HICOLOR) u8g.setHiColorByRGB(255,255,255);
}
void loop() {
potVal = analogRead(potPin);
potVal = (potVal - 512.0) / 512.0; // Normaliza -1.0 a +1.0
Serial.print(potVal);
Serial.print("\n");
p = analogRead(potPin); // 0-1023
w = map(p, 0, 1023, 100, -100); // Valor exibido: +100 (UP) a -100 (DOWN)
m = map(p, 0, 1023, 90, 0); // Ângulo da agulha: 0 a 90 graus
// Ajuste para desenho da agulha (offset visual)
xx = m;
if (xx < 45) xx = xx + 135;
else xx = xx - 45;
// Loop de desenho do display
u8g.firstPage();
do {
gauge(xx);
} while (u8g.nextPage());
delay(10);
}
Nota: Se a direção da rotação estiver invertida, troque os últimos dois argumentos no map():
w = map(p, 0, 1023, -100, 100); // Inverte sinal
m = map(p, 0, 1023, 0, 90); // Inverte agulha
Script Python (arduinoElevatorTrim.py)
#!/usr/bin/python
import sys
import serial
from socket import *
host = "localhost"
port = 21567
addr = (host, port)
UDPSock = socket(AF_INET, SOCK_DGRAM)
# AJUSTE: Porta serial do Arduino (Windows: COMx, Linux: /dev/ttyUSBx)
tty = "COM4"
print("tty is", tty)
try:
ser = serial.Serial(tty, 9600)
except:
print("Error connecting to", tty)
sys.exit(1)
prevline = ""
while True:
line = ser.readline().decode('utf-8').strip()
if line != prevline and line:
print(line)
UDPSock.sendto(line.encode('utf-8'), addr)
prevline = line
Importante: Se você abriu o Serial Monitor do Arduino IDE, feche-o e reconecte a placa antes de rodar o script Python.
Protocolo FlightGear (arduinoElevatorTrim.xml)
Copie este arquivo para <FlightGearRoot>/data/protocol/:
<?xml version="1.0"?>
<PropertyList>
<generic>
<input>
<line_separator>\n</line_separator>
<var_separator>,</var_separator>
<chunk>
<name>Elevator trim</name>
<node>/controls/flight/elevator-trim</node>
<type>float</type>
</chunk>
</input>
</generic>
</PropertyList>
Como Executar
- Carregue o sketch no Arduino Nano
- Inicie o FlightGear com o parâmetro:
--generic=socket,in,30,localhost,21567,udp,arduinoElevatorTrim
(Sem espaços! Significa: input, 30Hz, localhost, porta 21567, UDP, protocolo arduinoElevatorTrim) - Execute o script Python:
python arduinoElevatorTrim.py - Gire o potenciômetro – o trim do elevador no FlightGear responderá em tempo real
Recursos Adicionais
- Repositório GitHub: dciliberti/arduinoElevatorTrimOLED
- Esquemático Fritzing incluso (fios do display podem passar sob o Nano)
Processo de manufatura
- Dados Digital com Arduino: Gere Números Aleatórios 1-6 em LCD 16x2
- Construa um Homem de Ferro com Arduino: Componentes, Sensores e Guia Passo a Passo
- Relógio Analógico Estilo POV com LEDs – Projeto DIY Arduino Nano
- Find Me: Localizador Inteligente de Objetos com Arduino e Bluetooth
- Construa um Braço Robótico 3D Impresso Funcional com Arduino – Guia Passo a Passo
- Controlador de Umidificador DIY com Arduino e Relé – Configuração Segura de Alta Tensão
- Jogo Pong Neon em Matriz NeoPixel com Arduino Nano
- Volante Joystick Arduino Personalizado para Jogos
- Construa um Receptor FM Potente com Arduino e Módulo TEA5767
- Arduino 101: Construa um Pedômetro com Sensor DHT11 e Display LCD