[EM CONSTRUÇÃO/REVISÃO] Modelagem Matemática, Cinemática e Controle do Robô Otto#

Objetivos da aula#

  1. Descrever matematicamente a posição de uma perna articulada a partir dos ângulos das juntas (cinemática direta).

  2. Modelar o movimento oscilatório das juntas por funções senoidais.

  3. Calcular velocidade e aceleração angular e relacioná-las ao torque dos atuadores.

  4. Compreender a estrutura de um sistema de controle em malha fechada com controlador PID.

  5. Implementar e simular os modelos em software de computação numérica, tais como no MATLAB (ou Octave).

Note

Relação com problemas de engenharia civil

Os princípios desta aula têm análogos diretos em estruturas e dinâmica:

Conceito — robótica

Análogo — engenharia civil

Cinemática de perna articulada

Geometria de treliça com barras rotacionadas

Oscilação senoidal da junta

Vibração livre sob carga harmônica

Centro de massa do bípede

Centróide e condição de tombamento

Torque gravitacional sobre segmento

Momento fletor por carga excêntrica

Controlador PID em malha fechada

Amortecedor ativo sob ação sísmica

A matemática subjacente é a mesma; o sistema físico é diferente.


1. Cinemática direta de segmentos articulados#

Ao montar o robô Otto, você construiu um sistema físico com múltiplos atuadores, segmentos rígidos e restrições geométricas. Quando o Otto dá um passo, três fenômenos ocorrem simultaneamente: a geometria da estrutura se altera conforme os servos mudam de ângulo; a física impõe restrições de inércia e gravidade; e o controle reage continuamente, corrigindo desvios entre posição desejada e real.

Esta aula conecta esses três domínios para permitir compreender e diagnosticar quantitativamente o comportamento do robô.

1.1 Formulação do problema#

Cinemática descreve o movimento de corpos em termos de posição, velocidade e aceleração, sem considerar as forças causadoras. A cinemática direta resolve um problema específico: dados os ângulos de cada junta, qual é a posição do atuador final?

Note

Em robôs bípedes como o Otto, o atuador final é o pé. O problema é análogo a determinar a posição dos nós de uma treliça a partir das dimensões e orientações das barras.

1.2 Um segmento rotacionando#

Considere um segmento rígido de comprimento \(L\) fixado na origem. Quando forma um ângulo \(\theta\) com o eixo horizontal, as coordenadas de sua extremidade livre são:

\[ x = L\cos(\theta), \qquad y = L\sin(\theta) \]

O seno e o cosseno emergem da decomposição de um vetor rotacionado sobre dois eixos ortogonais — fundamento de toda a cinemática de sistemas articulados em cadeia aberta.

Hide code cell source

from IPython.display import HTML, display
import uuid

canvas_id = f"canvas_{uuid.uuid4().hex}"

display(HTML(f"""
<canvas id="{canvas_id}" width="600" height="600"
        style="border:1px solid #ccc;border-radius:10px;background:white;"></canvas>
<script>
(function() {{
    const canvas = document.getElementById("{canvas_id}");
    const ctx = canvas.getContext("2d");
    const L = 180, cx = 300, cy = 300;
    let theta = 0;
    function draw() {{
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        ctx.strokeStyle = "#e0e0e0"; ctx.lineWidth = 1;
        for(let i=0;i<=600;i+=50){{
            ctx.beginPath(); ctx.moveTo(i,0); ctx.lineTo(i,600); ctx.stroke();
            ctx.beginPath(); ctx.moveTo(0,i); ctx.lineTo(600,i); ctx.stroke();
        }}
        ctx.strokeStyle="#999"; ctx.lineWidth=2;
        ctx.beginPath(); ctx.moveTo(0,cy); ctx.lineTo(600,cy); ctx.stroke();
        ctx.beginPath(); ctx.moveTo(cx,0); ctx.lineTo(cx,600); ctx.stroke();
        const x = cx + L*Math.cos(theta);
        const y = cy - L*Math.sin(theta);
        ctx.strokeStyle="#1565c0"; ctx.lineWidth=6;
        ctx.beginPath(); ctx.moveTo(cx,cy); ctx.lineTo(x,y); ctx.stroke();
        ctx.fillStyle="#1565c0";
        ctx.beginPath(); ctx.arc(cx,cy,10,0,2*Math.PI); ctx.fill();
        ctx.fillStyle="red";
        ctx.beginPath(); ctx.arc(x,y,12,0,2*Math.PI); ctx.fill();
        ctx.fillStyle="#222"; ctx.font="18px Arial";
        ctx.fillText("θ = "+(theta*180/Math.PI).toFixed(1)+"°", 20, 30);
        theta += 0.0005;
        requestAnimationFrame(draw);
    }}
    draw();
}})();
</script>
"""))

1.2.1 Implementacao no MATLAB#

O arquivo Ex1_2_1_CinPerna.m plota a extremidade de um segmento rotacionando conforme o angulo varia – verificacao direta de \(x = L\cos\theta\), \(y = L\sin\theta\).

O código seguinte inicia o MATLAB pelo Python e adiciona automaticamente ao path do MATLAB toda a pasta matlab do repositório (incluindo subpastas), permitindo executar qualquer arquivo .m do projeto a partir deste notebook.

Hide code cell source

import os
import matlab.engine

eng = matlab.engine.start_matlab()

repo_root = os.path.abspath(os.path.join(os.getcwd(), "..", ".."))
matlab_path = os.path.join(repo_root, "matlab")

eng.eval(f"addpath(genpath('{matlab_path}'));", nargout=0)

O código seguinte executa o arquivo disponível no GitHub desta aula, diretamente neste notebook tendo o software Matlab integrado. Se preferir, clique para download do exemplo Ex1_2_1_CinPerna.m

Hide code cell source

eng.Ex1_2_1_CinPerna(nargout=0)

1.3 Dois segmentos em série — modelo de quadril e joelho#

A perna de um membro de robô (perna, braço) pode ser modelada como dois segmentos rígidos em série (comprimentos \(L_1\) e \(L_2\)). O primeiro gira com ângulo \(\theta_1\) em relação ao referencial global; o segundo gira com \(\theta_2\) em relação ao primeiro.

Posição da junta intermediária:

\[ x_1 = L_1\cos(\theta_1), \qquad y_1 = L_1\sin(\theta_1) \]

Posição do atuador final (pé), por acumulação de rotações:

\[ \boxed{x_2 = L_1\cos(\theta_1) + L_2\cos(\theta_1 + \theta_2)} \]
\[ \boxed{y_2 = L_1\sin(\theta_1) + L_2\sin(\theta_1 + \theta_2)} \]

O ângulo acumulado \((\theta_1 + \theta_2)\) é a orientação absoluta do segundo segmento. Para uma cadeia de \(n\) segmentos, o ângulo absoluto da \(i\)-ésima junta generaliza-se para \(\Theta_i = \sum_{k=1}^{i} \theta_k\).

Hide code cell source

from IPython.display import HTML
HTML("""<div style="border:1px solid #d0d0d0;border-radius:6px;padding:1.25rem;margin:1.5rem 0;background:#fafafa;">
<p style="font-size:0.8rem;font-weight:600;letter-spacing:0.06em;text-transform:uppercase;color:#555;margin:0 0 0.75rem;">Simulador — Cinemática direta de dois segmentos</p>
<canvas id="legCanvas" width="540" height="300" style="display:block;margin:0 auto;border:1px solid #e8e8e8;border-radius:4px;background:#fff;"></canvas>
<div style="max-width:540px;margin:0.75rem auto 0;">
  <div style="display:flex;align-items:center;gap:10px;margin-bottom:6px;">
    <span style="font-size:13px;font-family:monospace;min-width:100px;color:#333;">θ₁ (1ª junta)</span>
    <input type="range" id="th1" min="-70" max="70" value="30" style="flex:1;">
    <span style="font-size:13px;font-family:monospace;min-width:36px;color:#1a7a50;" id="th1val">30°</span>
  </div>
  <div style="display:flex;align-items:center;gap:10px;">
    <span style="font-size:13px;font-family:monospace;min-width:100px;color:#333;">θ₂ (2ª junta)</span>
    <input type="range" id="th2" min="-70" max="70" value="20" style="flex:1;">
    <span style="font-size:13px;font-family:monospace;min-width:36px;color:#2563a8;" id="th2val">20°</span>
  </div>
  <p style="font-size:12px;font-family:monospace;color:#666;text-align:center;margin-top:8px;" id="footpos">Calculando...</p>
</div></div>
<script>
(function(){
  var cv=document.getElementById('legCanvas'), ctx=cv.getContext('2d');
  var L=110, cx=270, cy=120;
  function draw(){
    var t1=parseFloat(document.getElementById('th1').value)*Math.PI/180;
    var t2=parseFloat(document.getElementById('th2').value)*Math.PI/180;
    document.getElementById('th1val').textContent=Math.round(t1*180/Math.PI)+'°';
    document.getElementById('th2val').textContent=Math.round(t2*180/Math.PI)+'°';
    var x1=cx+L*Math.cos(t1), y1=cy-L*Math.sin(t1);
    var x2=x1+L*Math.cos(t1+t2), y2=y1-L*Math.sin(t1+t2);
    ctx.clearRect(0,0,540,300);
    ctx.strokeStyle='#e8e8e8'; ctx.lineWidth=0.5;
    for(var i=0;i<=540;i+=40){ctx.beginPath();ctx.moveTo(i,0);ctx.lineTo(i,300);ctx.stroke();}
    for(var j=0;j<=300;j+=40){ctx.beginPath();ctx.moveTo(0,j);ctx.lineTo(540,j);ctx.stroke();}
    ctx.strokeStyle='#bbb'; ctx.lineWidth=1;
    ctx.beginPath();ctx.moveTo(0,cy);ctx.lineTo(540,cy);ctx.stroke();
    ctx.beginPath();ctx.moveTo(cx,0);ctx.lineTo(cx,300);ctx.stroke();
    ctx.strokeStyle='#1a7a50'; ctx.lineWidth=5; ctx.lineCap='round';
    ctx.beginPath();ctx.moveTo(cx,cy);ctx.lineTo(x1,y1);ctx.stroke();
    ctx.strokeStyle='#2563a8'; ctx.lineWidth=5;
    ctx.beginPath();ctx.moveTo(x1,y1);ctx.lineTo(x2,y2);ctx.stroke();
    [[cx,cy,'#1a7a50',7],[x1,y1,'#888',5],[x2,y2,'#c0392b',7]].forEach(function(p){
      ctx.beginPath();ctx.arc(p[0],p[1],p[3],0,2*Math.PI);ctx.fillStyle=p[2];ctx.fill();
    });
    ctx.font='12px monospace'; ctx.fillStyle='#1a7a50';
    ctx.fillText('θ₁='+Math.round(t1*180/Math.PI)+'°',cx+8,cy-10);
    ctx.fillStyle='#2563a8';
    ctx.fillText('θ₂='+Math.round(t2*180/Math.PI)+'°',x1+8,y1-8);
    ctx.fillStyle='#c0392b'; ctx.font='bold 12px monospace';
    ctx.fillText('pé (x₂, y₂)',x2+8,y2+4);
    var rx=((x2-cx)/L).toFixed(3), ry=((-(y2-cy))/L).toFixed(3);
    document.getElementById('footpos').textContent='x₂ = '+rx+' L    y₂ = '+ry+' L   (normalizado por L)';
  }
  document.getElementById('th1').addEventListener('input',draw);
  document.getElementById('th2').addEventListener('input',draw);
  draw();
})();
</script>""")

Simulador — Cinemática direta de dois segmentos

θ₁ (1ª junta) 30°
θ₂ (2ª junta) 20°

Calculando...

1.3.1 Implementacao no MATLAB – cinematica estatica#

O arquivo Ex1_3_1_DoisSegm.m calcula e plota a configuracao da perna para angulos fixos. Altere theta1 e theta2 e observe o deslocamento do pe.

Baixar Ex1_3_1_DoisSegm.m no GitHub

Hide code cell source

eng.Ex1_3_1_DoisSegm(nargout=0)

1.4 Modelo cinemático simplificado do Otto bípede#

O Otto difere de um manipulador planar clássico: seus movimentos distribuem‑se em dois planos independentes, controlados por dois pares de servos.


Robô Otto Bípede: estrutura bípede com 4 servomotores
  • Servos do quadril (superiores, posição S1 e S2): cada servo gira a perna correspondente lateralmente em torno do eixo longitudinal do corpo (eixo frente–trás), fazendo o corpo inclinar para um dos lados.

  • Servos dos pés (inferiores, posição S3 e S4): cada servo inclina a plataforma do pé no plano frontal, levantando ou abaixando o respectivo lado do corpo.

A animação abaixo ilustra o padrão de caminhada resultante desses dois movimentos combinados:

Otto robô dançando — exemplo de caminhada bípede
Exemplo de locomoção bípede com movimentos laterais sincronizados

Movimento lateral do quadril#

O servo do quadril gira a perna em torno de um eixo vertical imaginário alinhado ao corpo. Para pequenos ângulos, o deslocamento lateral \(x\) da extremidade inferior da perna (comprimento \(L\)) é:

\[ x(t) = L\,\sin(\theta_h(t)) \]

Durante a caminhada, esse ângulo oscila senoidalmente com amplitude \(A\) e frequência angular \(\omega\):

\[ \theta_h(t) = A\,\sin(\omega\,t) \]

A oscilação transfere o centro de massa lateralmente de uma perna para a outra — condição necessária para que a perna oposta seja liberada do solo e avance.

Parâmetros típicos do Otto: \(L \approx 60\,\text{mm}\), \(A \approx 20°\), \(\omega = 2\pi f\) com \(f \approx 0{,}5\,\text{Hz}\).

Movimento de inclinação dos pés#

Os servos dos pés levantam fisicamente um lado do corpo, complementando o deslocamento lateral do quadril. A altura efetiva do corpo \(y\) em função do ângulo do servo do pé \(\theta_f\) é modelada como:

\[ y(t) = h - r\,\cos(\theta_f(t)) \]

onde \(h\) é a distância entre o eixo do servo do pé e o chão, e \(r\) é o raio geométrico efetivo do mecanismo (distância do eixo do servo à extremidade do pé que toca o solo). Quando \(\theta_f = 0\) (pé horizontal), \(y = h - r\) é mínimo (pé totalmente apoiado); quando \(\theta_f > 0\), o lado correspondente do corpo sobe.

Nota sobre a fórmula \(y = h + r\sin(\theta_f)\): essa forma alternativa é equivalente quando a origem de \(\theta_f\) é definida na posição vertical (\(\theta_f = 0\) corresponde ao pé erguido), o que varia conforme a convenção de montagem. Adotamos aqui a convenção de que \(\theta_f = 0\) é a posição neutra (pé horizontal).

Os dois pés oscilam em oposição de fase (\(\Delta\phi = \pi\)):

\[ \theta_{f,\text{esq}}(t) = A_f\,\sin(\omega\,t), \qquad \theta_{f,\text{dir}}(t) = A_f\,\sin(\omega\,t + \pi) = -A_f\,\sin(\omega\,t) \]

Quando o pé esquerdo levanta o corpo, o pé direito o abaixa, produzindo uma inclinação controlada que se sincroniza com o movimento lateral do quadril.