Skip to content

ZENIT vem da palavra zênite, que é o ponto mais alto do céu em relação ao observador — o ponto de equilíbrio máximo. O nome foi escolhido porque o projeto representa precisão, estabilidade e controle, assim como o zênite simboliza o ápice e o centro perfeito no firmamento.

License

Notifications You must be signed in to change notification settings

emanueca/zenit_science

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

99 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ZENIT — PID Balance (Gangorra)

Slogan: Código vs. Gravidade

Resumo: Este protótipo didático estabiliza uma bolinha de pingue-pongue em uma gangorra 1D usando Arduino UNO, um sensor de distância Sharp GP2Y0A21 e um servo padrão. O Arduino mede a distância da bola, calcula o erro e aplica um controlador PID para inclinar a barra, mantendo a esfera em equilíbrio.


1) Código principal (Arduino UNO)

O código a seguir é baseado no tutorial do canal ELECTRONOOBS; use-o como referência inicial. Ajuste os ganhos Kp, Ki e Kd, o setpoint e o mapeamento conforme a sua mecânica. O firmware oficial e aprimorado que usamos no projeto está disponível em assets/code/index/pid_balance no repositório — esta página apresenta apenas o código de base de terceiros.

/* PID balance code with ping pong ball and distance sensor sharp 2y0a21
 *  by ELECTRONOOBS: https://www.youtube.com/channel/UCjiVhIvGmRZixSzupD0sS9Q
 *  Tutorial: http://electronoobs.com/eng_arduino_tut100.php
 *  Code: http://electronoobs.com/eng_arduino_tut100_code1.php
 *  Scheamtic: http://electronoobs.com/eng_arduino_tut100_sch1.php
 *  3D parts: http://electronoobs.com/eng_arduino_tut100_stl1.php   
 */
#include <Wire.h>
#include <Servo.h>

///////////////////////Inputs/outputs///////////////////////
int Analog_in = A0;
Servo myservo;  // create servo object to control a servo, later attatched to D9
///////////////////////////////////////////////////////

////////////////////////Variables///////////////////////
int Read = 0;
float distance = 0.0;
float elapsedTime, time, timePrev;        //Variables for time control
float distance_previous_error, distance_error;
int period = 50;  //Refresh rate period of the loop is 50ms
///////////////////////////////////////////////////////

///////////////////PID constants///////////////////////
float kp=8; //Mine was 8
float ki=0.2; //Mine was 0.2
float kd=3100; //Mine was 3100
float distance_setpoint = 21;           //Should be the distance from sensor to the middle of the bar in mm
float PID_p, PID_i, PID_d, PID_total;
///////////////////////////////////////////////////////

void setup() {
  Serial.begin(9600);
  myservo.attach(9);  // attaches the servo on pin 9 to the servo object
  myservo.write(125); //Put the servo at angle 125, so the balance is in the middle
  pinMode(Analog_in,INPUT);
  time = millis();
}

void loop() {
  if (millis() > time+period)
  {
    time = millis();
    distance = get_dist(100);
    distance_error = distance_setpoint - distance;
    PID_p = kp * distance_error;
    float dist_difference = distance_error - distance_previous_error;
    PID_d = kd*((distance_error - distance_previous_error)/period);

    if(-3 < distance_error && distance_error < 3)
    {
      PID_i = PID_i + (ki * distance_error);
    }
    else
    {
      PID_i = 0;
    }

    PID_total = PID_p + PID_i + PID_d;
    PID_total = map(PID_total, -150, 150, 0, 150);

    if(PID_total < 20){PID_total = 20;}
    if(PID_total > 160) {PID_total = 160; }

    myservo.write(PID_total+30);
    distance_previous_error = distance_error;
  }
}

float get_dist(int n)
{
  long sum=0;
  for(int i=0;i<n;i++)
  {
    sum=sum+analogRead(Analog_in);
  }
  float adc=sum/n;
  float distance_cm = 17569.7 * pow(adc, -1.2062);
  return(distance_cm);
}

Dica: se a gangorra se inclinar para o lado errado, inverta o sinal (troque distance_setpoint - distance por distance - distance_setpoint) ou ajuste o lado mecânico do servo.


2) Materiais (BOM) — incluindo as peças 3D e opcionais

Além dos itens essenciais, listamos algumas peças opcionais que podem aprimorar a experiência, como fonte de 7 V (para motores mais robustos), buzzer e LED com resistores, e um capacitor extra para filtrar o sensor.

GrupoItemQtd.Observações
ControleArduino UNO (ou compatível)116 MHz; USB para programação
SensorSharp GP2Y0A21 (10–80 cm)1Apontado para a bola; fixar firme; cabo 3 vias
AtuaçãoServo padrão (ex.: Futaba S3003)14,8–6 V; torque típico 3–4 kg·cm (para 1D é suficiente)
EnergiaFonte 5 V externa (≥ 2 A)1Não alimente servo pela USB
Fonte 7 V (opcional)1Para quem deseja explorar servos de maior torque; use com regulador adequado
Capacitor 100–470 µF (5 V)1Próximo ao servo (anti-ruído) e outro opcional junto ao sensor para filtrar picos
ConexõesProtoboard + jumpersGND comum entre Arduino e fonte dos servos; inclua resistores (220–330 Ω) para LED e buzzer
LED (opcional)1Indicador visual de centragem; usar com resistor
Buzzer (opcional)1Alarme sonoro para quando a bola estiver equilibrada; usar com resistor
BolaBolinha de pingue-pongue1Superfície fosca ajuda o IR
Estrutura (3D / laser)Base inferior1Chapa 200×200 mm (MDF 3 mm / acrílico)
Suporte do servo (3D)1Suporte em L com furação padrão do servo
Braço / berço da gangorra (3D)1Peça central que apoia a barra; encaixe no pivô
Pivô / fulcro (3D ou parafuso + bucha)1Pode usar parafuso M4 + porcas/arruelas; opcionalmente rolamento 608
Barra da gangorra1200–250 mm de comprimento; canal raso central para a bola
Suporte do Sharp (3D)1Mantém o sensor apontado e na altura correta
Adaptador para horn (3D)1Acopla o horn do servo à barra (ou bieleta curta)
Espaçadores / colunas (3D)4Fixação entre base e nível da barra
Abas / fixadores (3D)2–4Para prender cabos/sensor na base
Protoboard (opcional)1Facilita a montagem provisória; inclua resistores para LED e buzzer

As peças impressas em 3D correspondem ao que se vê no protótipo: suporte do servo, berço/pivô da barra, suporte do sensor, adaptador para horn e espaçadores. Todos os arquivos STL estão em assets/files/3dFiles do repositório.

2.1) Peças usadas e comparações de hardware

Para orientar futuras montagens, a tabela abaixo resume três cenários: básico, usado no protótipo e recomendado. Assim fica fácil visualizar a evolução do projeto e escolher componentes conforme o seu orçamento e objetivo.

ComponenteBásico (baixo custo)Usado no protótipoRecomendado (melhorado)
Sensor de distânciaSharp GP2Y0A21 (10–80 cm) — sujeito a ruídos e saturaçãoSharp GP2Y0A21 (10–80 cm)Sharp GP2Y0A02 (8–110 cm) ou sensor time-of-flight (VL53L0X/VL53L1X) — maior alcance e estabilidade
ServoServos de baixo custo (analógicos, engrenagens plásticas) — podem não aguentar acrílico ou torque; em alguns casos, substitua a base por isopor para reduzir o pesoFutaba S3003Servos de maior torque com engrenagens metálicas (MG996R, DS3218) — melhor precisão
Placa controladoraArduino UNO clone genéricoArduino UNO originalESP32 (ou ESP32-S3) — mais RAM, Wi-Fi/Bluetooth integrados e possibilidades de expansão
Fonte de alimentação5 V / 1 A — suficiente para servos leves5 V / 2 A — utilizada no protótipo, alimenta servo padrão com folga5–7 V / ≥ 3 A com regulador DC-DC — para servos de torque elevado e múltiplos periféricos
EstruturaMDF fino ou isopor — menor custo, mas pode ser menos rígido e durávelAcrílico como base para a bola rolar e como suporte de todos os componentes do servo/motor (impressão 3D PLA para peças auxiliares)Estruturas 3D impressas em PLA/ABS com reforços ou acrílico/alumínio usinado — maior rigidez e acabamento profissional

Observações: nas versões básicas, servos analógicos de baixo custo podem não ter torque suficiente e o acrílico pode trincar; considere usar isopor para reduzir o peso. O protótipo utilizou Futaba S3003, acrílico como base e PLA impresso em 3D para suportes. A versão recomendada sugere o ESP32 por oferecer mais memória e conectividade (Wi-Fi/Bluetooth), além de servos de maior torque e sensores Sharp de maior alcance.

2.2) Datasheets

Os manuais técnicos (datasheets) dos componentes estão disponíveis na pasta zenit_science/datasheets na raiz do repositório. Consulte esses documentos para detalhes de pinagem, curvas de resposta, limites de operação e características elétricas. Para referência rápida:

  • Datasheet do servo Futaba S3003 (Luxorparts) — especifica torque (3,2 kg·cm a 4,8 V; 4,1 kg·cm a 6 V), velocidade (0,19 s/60° a 6 V), corrente máxima (< 1 A) e outras características.
  • Datasheet do Sharp GP2Y0A21 — destaca a faixa de medição de 10 a 80 cm e a resposta típica de 39 ms, bem como a corrente de operação típica de 30 mA.
  • Datasheet oficial do Sharp GP2Y0A21YK — abrangente (veja diretório de datasheets para download, pois o site pode estar instável).
  • Outros datasheets (MG996R, ESP32, etc.) também estão agrupados nessa pasta.

3) Ligações elétricas (UNO)

As ligações básicas permanecem as mesmas; caso opte por incluir LED e buzzer, conecte-os aos pinos indicados no firmware oficial (ledPin = 6, buzzerPin = 3) com resistores em série (~220 Ω para o LED e ~100 Ω para o buzzer). Não se esqueça de usar capacitores próximos ao servo e ao sensor para filtrar ruídos.

Sensor Sharp GP2Y0A21

  • Vcc → 5 V
  • GND → GND
  • OUT → A0 (igual ao Analog_in no código)

Servo (S3003)

  • Vermelho → 5 V da fonte externa
  • Marrom/Preto → GND (comum ao GND do Arduino)
  • Laranja/Branco (sinal) → D9

4) Montagem mecânica (1D)

  1. Base fixa (MDF/acrílico).
  2. Suporte do servo centralizado, horn alinhado ao centro da barra.
  3. Pivô/fulcro posicionado no centro da barra (reduz esforço do servo).
  4. Bola rola sobre a barra; o sensor Sharp deve ficar lateralmente apontando para a esfera (ou para a região central onde ela passa).
  5. Curso mecânico pequeno (±10–15°) evita saturação e melhora a estabilidade.

5) Tutorial interativo e calibrações

Este projeto vai além do sketch básico. Dentro do diretório assets do repositório GitHub você encontra todos os arquivos necessários para experimentar, calibrar e entender o sistema:

  • Firmware oficial: em assets/code/index/pid_balance está a versão que utilizamos na exposição. Ela inclui melhorias como filtro exponencial, zona morta (“deadband”), beep/LED quando a bola está estabilizada e histerese no servo. Leia o código e adapte os parâmetros conforme a sua mecânica.
  • Jogo PID: em assets/code/game/index há um pequeno jogo/programa interativo em que o usuário pode “brincar” de equilibrar a bola ajustando os ganhos PID. Ele registra placar e sons para tornar o experimento mais lúdico; embora seja um protótipo e não funcione tão bem quanto o firmware oficial, é útil para aprender como as constantes influenciam o comportamento.
  • Calibrações: nas pastas assets/calibra_buzzer, assets/calibra_sensor e assets/calibra_servo há sketches simples para testar o buzzer/LED, estimar a curva de distância do sensor e determinar o ângulo central do servo. Esses arquivos não são 100 % precisos, mas servem como base de calibração — ajuste os valores conforme o seu hardware e anote os resultados para usar no firmware principal.
  • Arquivos de impressão 3D e mídia: em assets/files/3dFiles estão os STL das peças do protótipo. O subdiretório assets/files também hospedará futuramente um banner e slides de apresentação para auxiliar na explicação do projeto.

Para utilizar os sketches de calibração:

  1. Abra o arquivo adequado (buzzer_centro, sensor_curve ou servo_zero, por exemplo) na IDE Arduino.
  2. Carregue no Arduino e siga as instruções do Serial Monitor para identificar o ponto em que o buzzer/LED deve acender, a curva real do sensor de distância e o ângulo central do servo.
  3. Anote os valores medidos e atualize os parâmetros no firmware oficial.

6) Calibração do Sharp GP2Y0A21 (10–80 cm)

A faixa doce para este sensor no contexto do projeto é entre 15 e 40 cm. Faça uma curva experimental: marque 15, 20, 25, 30 e 35 cm; leia analogRead() e confira a curva dist = 17569.7 × adc−1.2062. Se a leitura saturar muito perto ou muito longe, realoque o sensor ou ajuste o distance_setpoint. Luz ambiente e superfícies brilhantes podem atrapalhar — use anteparo (tubinho preto) no sensor e uma bola fosca.


7) Tuning do PID (prático)

  1. Comece com Ki = 0, Kd = 0; suba o Kp até começar a oscilar (margem).
  2. Adicione Kd para amortecer, reduzindo o overshoot.
  3. Introduza Ki aos poucos para remover o erro em regime; não exagere para não “embalar”.
  4. Use o Serial Plotter da IDE para enxergar o erro e a resposta.
  5. Dê pequenos toques na barra/bola e observe o tempo de acomodação.

8) Métricas que impressionam a banca e observações sobre o sensor

Algumas grandezas úteis para demonstrar o desempenho:

  • Overshoot (%) — pico inicial acima do setpoint.
  • Tempo de acomodação (s) — tempo até ficar estável (±5 %).
  • Erro estacionário — desvio final médio.
  • Taxa do loop (Hz) — com period = 50 ms a taxa é ≈ 20 Hz, mas pode ser reduzida para 20–30 ms se a mecânica permitir.
  • Filtros — o firmware oficial emprega filtro exponencial na leitura, histerese no servo e zona morta para evitar jitter.

Atenção ao comportamento do sensor: o Sharp GP2Y0A21 é modulado internamente. Como explica o artigo da Robot Research Lab, a modulação produz pulsos na saída que podem gerar ruído inesperado; se você ler o valor enquanto o sensor está atualizando, pode capturar picos de tensão até 1 V acima do valor real, dificultando leituras consistentes. Além disso, o sensor passa 32 ms transmitindo e apenas ~9 ms descansando, e não há maneira de saber exatamente quando o período de repouso ocorre. Quando a bola fica fora da faixa de detecção (longe do sensor), esses picos fazem a saída “ficar louca” — o famoso glitch de modulação. Adicionamos filtros e limitação de distância no firmware oficial para mitigar esse efeito, mas tenha ciência de que o bug é inerente à física do sensor.


9) Roadmap (opcional)

  • Expandir para 2D (plataforma com 2 servos) usando 4 sensores Sharp ou touch resistivo de 4 fios.
  • Implementar telemetria (plotagem x tempo) via Serial/Processing/Excel ou web.
  • Modo competição: medir o tempo em que a bola permanece no centro ou em checkpoints definidos.

10) Como rodar

  1. Abra a IDE Arduino e selecione Arduino UNO como placa.
  2. Se quiser testar o código base, cole o sketch apresentado no item 1. Para melhor desempenho, abra o arquivo pid_balance em assets/code/index e carregue-o no Arduino.
  3. Ligue o hardware: servo alimentado por fonte 5 V externa, LED e buzzer com resistores, GND comum.
  4. Faça a calibração do sensor e ajuste distance_setpoint; se necessário, use os sketches de calibração para estimar os valores corretos.
  5. Tune os ganhos Kp, Ki e Kd até estabilizar.
  6. Caso deseje, experimente o “jogo” PID em assets/code/game/index.

11) Segurança

  • Nunca alimente servos pesados pela porta USB.
  • Use capacitores próximos ao servo e ao sensor para atenuar ruído e picos.
  • Instale uma chave liga/desliga e mantenha os cabos bem fixos.

12) Licença & Créditos

Este projeto é de uso educacional. O sketch original foi criado por ELECTRONOOBS (links no cabeçalho do código). A equipe ZENIT (IFFar) adaptou, aprimorou o firmware e desenvolveu toda a documentação, peças 3D e material de apoio.

Quem quiser replicar ou derivar este projeto está livre para fazê-lo, desde que:

  • Mantenha os créditos a ELECTRONOOBS pelo código base e à equipe ZENIT (IFFar) pelas adaptações.
  • Cite o repositório oficial (github.com/emanueca/zenit_science) em qualquer material de divulgação.
  • Não remova as notas de fonte e créditos presentes no código.

Licença (GPL v3)

Este projeto está licenciado sob a GNU General Public License v3.0.

  • Você pode usar, estudar, modificar e redistribuir.
  • Trabalhos derivados devem manter a mesma licença (copyleft).
  • Veja o arquivo LICENSE para o texto integral (inglês + tradução PT-BR de referência).

About

ZENIT vem da palavra zênite, que é o ponto mais alto do céu em relação ao observador — o ponto de equilíbrio máximo. O nome foi escolhido porque o projeto representa precisão, estabilidade e controle, assim como o zênite simboliza o ápice e o centro perfeito no firmamento.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •