Programming Cosmic Dynamics in a Robot Car through variable inertia with NKTg Law

userHead Nguyen.Khanh Tung 2026-04-19 18:02:12 17 Views0 Replies

I'd like to share a robotics project that takes a different approach to motor control — instead of using PID, the robot uses a physics law called NKTg Law to decide when to brake, decelerate, or run normally.

🧪 The Core Idea

Classical physics treats mass as constant. But real robots change mass constantly — picking up cargo, dropping it, consuming battery. The NKTg Law by Nguyen Khanh Tung handles this directly:

NKTg = f(x, v, m)

NKTg₁ = x × m × v → Is the robot moving away from stable state?NKTg₂ = (dm/dt) × m × v → Is mass change affecting momentum?

This law was verified against real ESA Mars orbital data with only 0.208% error. Now it runs on an ESP32.

🛒 Parts List (~$55–$65 total)

ComponentPrice (USD)
ESP32 DevKit V1~$6
MPU6050 IMU~$2
Encoder 600PPR × 2~$6.50/each
Load Cell 5kg + HX711~$5
Motor Driver BTS7960~$6
DC Gear Motor 12V × 2 + wheels~$6/set
Li-ion 3S 11.1V 3000mAh~$10
Robot chassis 2WD/4WD~$6–$12

🔌 Wiring

 

 

MPU6050  → ESP32: SDA→GPIO21, SCL→GPIO22 HX711    → ESP32: DT→GPIO4,   SCK→GPIO5 Encoder L→ ESP32: A→GPIO34,   B→GPIO35 Encoder R→ ESP32: A→GPIO36,   B→GPIO39 BTS7960  → ESP32: RPWM→GPIO25, LPWM→GPIO26, EN→GPIO27 BTS7960  → Battery: 12V direct

⚙️ How Motor Control Works

The ESP32 runs 3 layers at 100Hz:

Layer 1 — Read sensors:

Encoder → position x (m) and velocity v (m/s)Load Cell → mass m (kg) and dm/dt (kg/s)MPU6050 → acceleration cross-check

Layer 2 — Compute NKTg:

 

 

cpp

float nktg1(float x, float v, float m) { return x * (m * v); } float nktg2(float dm_dt, float v, float m) { return dm_dt * (m * v); }

Layer 3 — Drive motors:

 

 

cpp

if (n1 > 500.0)       → emergency brake   // unstable else if (n2 < -50.0)  → slow down 50%     // sudden mass loss else                  → normal run        // stable

Layer 4 — Web dashboard at 20Hz: ESP32 streams x, v, m, dm/dt via USB Serial → open NKTg_System.html in Chrome/Edge → real-time charts.

📋 Full ESP32 Code

 

 

cpp

#include <Wire.h> #include <MPU6050.h> #include <HX711.h>  MPU6050 imu; HX711 loadcell;  #define ENC_L_A 34 #define ENC_L_B 35 #define MOTOR_RPWM 25 #define MOTOR_LPWM 26 #define MOTOR_EN   27 #define HX711_DT    4 #define HX711_SCK   5  volatile long encoderCount = 0; float x = 0, v = 0, m_prev = 0, m_curr = 0, dm_dt = 0;  const float WHEEL_CIRCUMFERENCE = 0.2; const int   PPR = 600; const float LOADCELL_SCALE = 2280.0; const unsigned long DT = 10; const unsigned long SEND_INTERVAL = 50; unsigned long lastTime = 0, lastSend = 0;  void IRAM_ATTR encoderISR() {   if (digitalRead(ENC_L_B) > 0) encoderCount++;   else encoderCount--; }  float nktg1(float x, float v, float m) { return x * (m * v); } float nktg2(float dm_dt, float v, float m) { return dm_dt * (m * v); }  void driveMotor(float n1, float n2) {   if (n1 > 500.0)      { ledcWrite(0, 0);   ledcWrite(1, 0); }   else if (n2 < -50.0) { ledcWrite(0, 90);  ledcWrite(1, 0); }   else                 { ledcWrite(0, 180); ledcWrite(1, 0); } }  void setup() {   Serial.begin(115200);   Wire.begin();   imu.initialize();   loadcell.begin(HX711_DT, HX711_SCK);   loadcell.set_scale(LOADCELL_SCALE);   loadcell.tare();   pinMode(ENC_L_A, INPUT_PULLUP);   pinMode(ENC_L_B, INPUT_PULLUP);   attachInterrupt(digitalPinToInterrupt(ENC_L_A), encoderISR, RISING);   ledcSetup(0, 5000, 8); ledcSetup(1, 5000, 8);   ledcAttachPin(MOTOR_RPWM, 0);   ledcAttachPin(MOTOR_LPWM, 1);   pinMode(MOTOR_EN, OUTPUT);   digitalWrite(MOTOR_EN, HIGH);   m_curr = loadcell.get_units(5);   m_prev = m_curr;   lastTime = millis();   Serial.println("READY"); }  void loop() {   unsigned long now = millis();   if (now - lastTime >= DT) {     float dt_sec = (now - lastTime) / 1000.0;     lastTime = now;     long count = encoderCount; encoderCount = 0;     float distance = (float)count / PPR * WHEEL_CIRCUMFERENCE;     v = distance / dt_sec;     x += distance;     if (loadcell.is_ready()) {       m_prev = m_curr;       m_curr = max(0.1f, loadcell.get_units());       dm_dt = (m_curr - m_prev) / dt_sec;     }     driveMotor(nktg1(x, v, m_curr), nktg2(dm_dt, v, m_curr));   }   if (now - lastSend >= SEND_INTERVAL) {     lastSend = now;     Serial.print(x, 3); Serial.print(",");     Serial.print(v, 3); Serial.print(",");     Serial.print(m_curr, 3); Serial.print(",");     Serial.println(dm_dt, 4);   } }

🎛️ Calibration Tips

Load Cell: Place a 1kg weight → adjust LOADCELL_SCALE until reading = 1.000 kgWheel: Measure actual circumference → update WHEEL_CIRCUMFERENCEThresholds: Start with 500 / −50, tune for your hardware

📖 Want to go deeper? (Drones, UAVs, Space Navigation)

This robot is just one application. The full book "Programming Cosmic Dynamics" covers NKTg across 11 programming languages — from Python to Assembly to Quantum Computing — with real ESA data validation.

Get the book:

🔹 Leanpub: https://leanpub.com/NKTgLaw (EN) | https://leanpub.com/NKTgLaw-vi (VI)🔹 Google Play: https://play.google.com/store/books/details?id=CNLKEQAAQBAJ&pli🔹 Amazon: https://www.amazon.com/dp/B0GTSBBRYR

Resources:

🌐 Live dashboard: https://traiphieu.com/nktg_system/💻 GitHub (150+ languages): https://github.com/NKTgLaw/NKTgLaw📄 DOI: 10.5281/zenodo.15808498

💬 Questions for the community

Has anyone tried replacing PID with a physics-based controller on ESP32?What sensors do you use to measure real-time mass changes on your robots?Would NKTg₂ (mass-momentum exchange) be useful for your drone or delivery robot projects?

Looking forward to your thoughts! 🚀

— Nguyen Khanh Tung | ORCID: 0009-0002-9877-4137 | traiphieu.com