Skip to main content

CODE of ANIMATION to be STUDIED (Create by CLAUDE): SISTEM ENCODER MOTOR - INTERAKTIF (PURE JS) aka Ilustrasi visual sederhana/diagram blok atau skema sensor pada motor listrik untuk menunjukkan bagaimana pengukuran kecepatan sudut dilakukan dalam sistem servo/stepper

Sistem Encoder Motor

Poros Motor
Disk Encoder (berlubang)
LED
👁️
Sensor Photo/IR
Proses Perhitungan
Pulsa ON/OFF
0
Δθ (rad)
0.000
÷
Δt (detik)
0.000
=
ω (rad/s)
0
Cara Kerja:
  • LED memancarkan cahaya ke sensor melalui disk.
  • Saat lubang lewat, cahaya terdeteksi → Pulsa ON.
  • Saat bagian padat lewat, cahaya terblokir → Pulsa OFF.
  • Setiap pulsa = perubahan sudut (Δθ).
  • Kecepatan sudut (ω) = Δθ / Δt.

SOURCE-CODE

<!--===============================-->
<!--SISTEM ENCODER MOTOR - INTERAKTIF (PURE JS)-->
<!--===============================-->

<style>
  .encoder-root {
    width: 100%;
    min-height: 100vh;
    box-sizing: border-box;
    background: linear-gradient(to bottom right, #0f172a, #1e293b);
    padding: 40px 16px;
    display: flex;
    flex-direction: column;
    align-items: center;
    font-family: Arial, Helvetica, sans-serif;
    color: #e5e7eb;
  }

  .encoder-title {
    font-size: 32px;
    font-weight: bold;
    margin-bottom: 32px;
    text-align: center;
  }

  .encoder-label-blue {
    color: #60a5fa;
    font-weight: 600;
    margin-bottom: 8px;
  }

  .encoder-label-green {
    color: #34d399;
    font-weight: 600;
    margin-bottom: 12px;
  }

  .encoder-shaft {
    width: 8px;
    height: 70px;
    background: linear-gradient(#4b5563, #9ca3af);
    margin: 0 auto;
  }

  .encoder-disk-wrapper {
    text-align: center;
    margin-top: 20px;
  }

  .encoder-disk {
    width: 260px;
    height: 260px;
    border-radius: 50%;
    background: linear-gradient(to bottom right, #4b5563, #6b7280);
    border: 5px solid #6b7280;
    position: relative;
    box-shadow: 0 0 30px rgba(0,0,0,0.4);
    margin: 0 auto;
    transition: transform 0.016s linear;
  }

  .encoder-center {
    width: 35px;
    height: 35px;
    background: #1f2937;
    border-radius: 50%;
    border: 2px solid #4b5563;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
  }

  .encoder-hole {
    width: 22px;
    height: 22px;
    background: #020617;
    border-radius: 50%;
    border: 1px solid #111827;
    position: absolute;
    transform: translate(-50%, -50%);
  }

  .encoder-row-led-sensor {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 40px;
    margin-top: 24px;
  }

  .encoder-icon-label {
    text-align: center;
  }

  .encoder-icon {
    font-size: 28px;
    margin-bottom: 4px;
    transition: transform 0.2s;
  }

  .encoder-led-active { color:#facc15; animation:encoder-pulse 0.8s infinite; }
  .encoder-led-inactive { color:#f59e0b; }
  .encoder-sensor-active { color:#22d3ee; }
  .encoder-sensor-inactive { color:#0e7490; }

  .encoder-beam {
    width: 120px;
    height: 4px;
    background: linear-gradient(to right,#facc15,#fb923c);
    opacity: 0.6;
  }

  .encoder-button {
    margin-top: 30px;
    padding: 12px 28px;
    border-radius: 10px;
    border:none;
    font-weight:bold;
    font-size:18px;
    color:#ffffff;
    cursor:pointer;
    box-shadow:0 5px 15px rgba(0,0,0,0.4);
    transition: transform 0.1s, background 0.15s;
  }

  .encoder-button:active { transform:scale(0.96); }
  .encoder-button-start { background:#16a34a; }
  .encoder-button-start:hover { background:#15803d; }
  .encoder-button-stop { background:#dc2626; }
  .encoder-button-stop:hover { background:#b91c1c; }

  .encoder-panel {
    margin-top:40px;
    background:#1e293b;
    border:1px solid #334155;
    border-radius:12px;
    padding:25px;
    width:100%;
    max-width:550px;
    text-align:center;
  }

  .encoder-panel-title {
    font-size:22px;
    font-weight:bold;
    margin-bottom:20px;
  }

  .encoder-flow-row {
    display:flex;
    justify-content:center;
    align-items:center;
    gap:20px;
    flex-wrap:wrap;
  }

  .encoder-flow-label { font-size:13px; color:#94a3b8; }
  .encoder-flow-value {
    font-family:"Courier New", monospace;
    font-weight:bold;
    font-size:26px;
  }

  .encoder-flow-arrow { font-size:26px; color:#64748b; }

  .encoder-value-pulse { color:#34d399; }
  .encoder-value-theta { color:#60a5fa; }
  .encoder-value-dt { color:#c084fc; }
  .encoder-value-omega { color:#facc15; font-size:32px; }

  .encoder-infobox {
    margin-top:25px;
    background:rgba(30,64,175,0.4);
    border-radius:12px;
    padding:20px;
    max-width:550px;
    color:#bfdbfe;
    font-size:14px;
  }

  .encoder-infobox ul {
    margin-top:10px;
    padding-left:20px;
    line-height:1.6;
  }

  @keyframes encoder-pulse {
    0% { transform:scale(1); opacity:1; }
    50% { transform:scale(1.15); opacity:0.7; }
    100% { transform:scale(1); opacity:1; }
  }
</style>

<div class="encoder-root" id="encoder-app">
  <h1 class="encoder-title">Sistem Encoder Motor</h1>

  <!--Poros Motor-->
  <div style="margin-bottom:20px; text-align:center;">
    <div class="encoder-label-blue">Poros Motor</div>
    <div class="encoder-shaft"></div>
  </div>

  <!--Disk Encoder-->
  <div class="encoder-disk-wrapper">
    <div class="encoder-label-green">Disk Encoder (berlubang)</div>
    <div class="encoder-disk" id="encoder-disk">
      <div class="encoder-center"></div>
      <!--Lubang akan diisi via JavaScript-->
    </div>
  </div>

  <!--LED & Sensor-->
  <div class="encoder-row-led-sensor">
    <div class="encoder-icon-label">
      <div class="encoder-icon encoder-led-inactive" id="encoder-led">⚡</div>
      <div style="color:#facc15; font-weight:600;">LED</div>
    </div>

    <div class="encoder-beam"></div>

    <div class="encoder-icon-label">
      <div class="encoder-icon encoder-sensor-inactive" id="encoder-sensor">👁️</div>
      <div style="color:#22d3ee; font-weight:600;">Sensor Photo/IR</div>
    </div>
  </div>

  <!--Button-->
  <button class="encoder-button encoder-button-start" id="encoder-button">
    START Motor
  </button>

  <!--Panel Proses Perhitungan-->
  <div class="encoder-panel">
    <div class="encoder-panel-title">Proses Perhitungan</div>

    <div class="encoder-flow-row">
      <div>
        <div class="encoder-flow-label">Pulsa ON/OFF</div>
        <div class="encoder-flow-value encoder-value-pulse" id="encoder-pulse">0</div>
      </div>

      <div class="encoder-flow-arrow">→</div>

      <div>
        <div class="encoder-flow-label">Δθ (rad)</div>
        <div class="encoder-flow-value encoder-value-theta" id="encoder-dtheta">0.000</div>
      </div>

      <div class="encoder-flow-arrow">÷</div>

      <div>
        <div class="encoder-flow-label">Δt (detik)</div>
        <div class="encoder-flow-value encoder-value-dt" id="encoder-dt">0.000</div>
      </div>

      <div class="encoder-flow-arrow">=</div>

      <div>
        <div class="encoder-flow-label">ω (rad/s)</div>
        <div class="encoder-flow-value encoder-value-omega" id="encoder-omega">0</div>
      </div>
    </div>
  </div>

  <!--Info Box-->
  <div class="encoder-infobox">
    <strong>Cara Kerja:</strong>
    <ul>
      <li>LED memancarkan cahaya ke sensor melalui disk.</li>
      <li>Saat lubang lewat, cahaya terdeteksi → Pulsa ON.</li>
      <li>Saat bagian padat lewat, cahaya terblokir → Pulsa OFF.</li>
      <li>Setiap pulsa = perubahan sudut (Δθ).</li>
      <li>Kecepatan sudut (ω) = Δθ / Δt.</li>
    </ul>
  </div>

</div>

<script>
(function() {

  var holes = 12;
  var rotation = 0;
  var isRunning = false;
  var pulseCount = 0;
  var lastPulseTime = null;
  var intervalId = null;

  var diskEl = document.getElementById('encoder-disk');
  var buttonEl = document.getElementById('encoder-button');
  var pulseEl = document.getElementById('encoder-pulse');
  var dthetaEl = document.getElementById('encoder-dtheta');
  var dtEl = document.getElementById('encoder-dt');
  var omegaEl = document.getElementById('encoder-omega');
  var ledEl = document.getElementById('encoder-led');
  var sensorEl = document.getElementById('encoder-sensor');

  (function createHoles() {
    var radius = 100;
    for (var i=0; i<holes; i++) {
      var angle = (i * 360) / holes;
      var rad = (angle - 90) * Math.PI/180;
      var x = 130 + radius * Math.cos(rad);
      var y = 130 + radius * Math.sin(rad);

      var hole = document.createElement('div');
      hole.className = 'encoder-hole';
      hole.style.left = x + 'px';
      hole.style.top  = y + 'px';
      diskEl.appendChild(hole);
    }
  })();

  var deltaTheta = (2 * Math.PI) / holes;
  dthetaEl.textContent = deltaTheta.toFixed(3);

  function setRunningState(running) {
    isRunning = running;

    if (running) {
      buttonEl.textContent = 'STOP Motor';
      buttonEl.classList.remove('encoder-button-start');
      buttonEl.classList.add('encoder-button-stop');

      ledEl.classList.remove('encoder-led-inactive');
      ledEl.classList.add('encoder-led-active');

      sensorEl.classList.remove('encoder-sensor-inactive');
      sensorEl.classList.add('encoder-sensor-active');

      pulseCount = 0;
      pulseEl.textContent = '0';
      dtEl.textContent = '0.000';
      omegaEl.textContent = '0';
      lastPulseTime = null;
      rotation = 0;
      diskEl.style.transform = 'rotate(0deg)';

      startLoop();
    } else {
      buttonEl.textContent = 'START Motor';
      buttonEl.classList.remove('encoder-button-stop');
      buttonEl.classList.add('encoder-button-start');

      ledEl.classList.remove('encoder-led-active');
      ledEl.classList.add('encoder-led-inactive');

      sensorEl.classList.remove('encoder-sensor-active');
      sensorEl.classList.add('encoder-sensor-inactive');

      stopLoop();
    }
  }

  function startLoop() {
    if (intervalId !== null) return;

    intervalId = setInterval(function() {
      var prevRotation = rotation;
      rotation = (rotation + 3) % 360;
      diskEl.style.transform = 'rotate(' + rotation + 'deg)';

      var segSize = 360 / holes;
      var prevIndex = Math.floor(prevRotation / segSize);
      var newIndex  = Math.floor(rotation / segSize);

      if (prevIndex !== newIndex) {
        var now = (window.performance && performance.now)
                  ? performance.now()
                  : Date.now();

        if (lastPulseTime !== null) {
          var deltaT = (now - lastPulseTime) / 1000;
          var omega = deltaTheta / deltaT;

          dtEl.textContent = deltaT.toFixed(3);
          omegaEl.textContent = omega.toFixed(2);
        }

        lastPulseTime = now;
        pulseCount += 1;
        pulseEl.textContent = String(pulseCount);
      }

    }, 16); 
  }

  function stopLoop() {
    if (intervalId !== null) {
      clearInterval(intervalId);
      intervalId = null;
    }
  }

  buttonEl.addEventListener('click', function() {
    setRunningState(!isRunning);
  });

})();
</script>

Comments

Popular posts from this blog

PART 0.1.0 RAD PROTOTYPE Web-App: Post-Video & Comments [program]

Video List — JP Kanji Ultra Translation CONTROL SECTION — Login (Admin) Username: Password: Login CONTROL SECTION — Admin Panel Enable Comments Disable Comments Logout Activity Log Show Video COMMENTS DISABLED BY ADMIN Leave a Comment: Additional Comment Show Video COMMENTS DISABLED BY ADMIN Leave a Comment: Additional Comment Show Video COMMENTS DISABLED BY ADMIN Leave a Comment: Additional Comment Show Video COMMENTS DISABLED BY ADMIN Leave a Comment: Additional Comment

My Pending and Delayed POSTs SUMMARY [APPs]
MADE by ChatGPT

🔗 My Pending and Delayed POSTs SUMMARY Sort by Date Sort by Auto Title Sort by My Title Ascending Descending (Newest First) Insert URL: Your Own Title (Optional): Status: Pending Done ➕ ADD ENTRY 💾 SAVE EDIT (MAIN FORM) DATE / TIME AUTO TITLE MY TITLE STATUS URL ACTIONS 📝 TO DO LIST SUMMARY Sort by Date Sort by Header Sort by Detail ...

Tablet Holder di Mobil dan Konsep DOUBLE Tablet Holder aka +secondary supporting holder

Gw udah pasang Holder khusus Tablet yg menurut gw sudah pilihan terbaik! Karena memiliki Arm KERAS/RIGID yg dibutuhkan utk menggenggam ERAT Dalam hal menopang Tablet yg lebih berat dr HP biasa Cekidot Lapak (click here!!) Namun .. Setelah gw pasang Bukan tidak bagus Tapi kalau melewati jalan jelek GOYANG (sikit) juga Gan! Akan tetapi .... Gw rasa bisa makin dimaksimalkan KERIGIDAN dengan menambah PENOPANG KEDUA Check it out: Dari searching2 di MarketPlace Gw ketemu yg mirip holder lampu belajar zaman doeloe Dan .. namun .. tiba2 gw menemukan Ide (lanjutan) Mekanisme yg bisa diReApplied kalau suatu saat diperlukan di Kreasi Agan2 lain  Gunakan Kombo 2 Perangkat berikut apabila membutuhkan holdingan tablet tambahan yg memiliki  "hold area"  yg lebih sempit karena holder kedua "takutnya/dirasa" tidak akan muat utk menggenggam Tablet sebagai penopang kedua, sebagai akibat holder pertama/utama sudah "cukup banyak" memakan tempat Perangkat Pertama (kon...