Created
May 16, 2020 12:30
-
-
Save ggerganov/092b86a59fa34926998953701ae22ca1 to your computer and use it in GitHub Desktop.
Automatic ISS Docking in Javascript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Auto-pilot for docking with the International Space Station | |
// | |
// The program uses Artificial Intelligence and Decision Trees (i.e. basic kinematics and a bunch of if statements) | |
// to perform docking with the ISS from any starting position. | |
// | |
// To use it: | |
// - open the SpaceX simulation website: https://iss-sim.spacex.com/ | |
// - open the Developer's console and paste the contents of this file | |
// | |
// Demo: https://youtu.be/jWQQH2_UGLw | |
// | |
function el(v) { return document.getElementById(v); } | |
function blink(e) { e.style.backgroundColor='red'; setTimeout(()=>{ e.style.backgroundColor=''; }, 100); } | |
// Sensor data | |
function getPitch(i) { return parseFloat(el('pitch').children[i].innerText); } | |
function getYaw(i) { return parseFloat(el('yaw').children[i].innerText); } | |
function getRoll(i) { return parseFloat(el('roll').children[i].innerText); } | |
function getRange() { return parseFloat(el('range').children[1].innerText); } | |
function getRangeX() { return parseFloat(el('x-range').children[0].innerText); } | |
function getRangeY() { return parseFloat(el('y-range').children[0].innerText); } | |
function getRangeZ() { return parseFloat(el('z-range').children[0].innerText); } | |
function getRate() { return parseFloat(el('rate').children[1].innerText); } | |
// Controls | |
function moveForward() { e = el('translate-forward-button'); blink(e); e.click(); } | |
function moveBackward() { e = el('translate-backward-button'); blink(e); e.click(); } | |
function moveUp() { e = el('translate-up-button'); blink(e); e.click(); } | |
function moveDown() { e = el('translate-down-button'); blink(e); e.click(); } | |
function moveLeft() { e = el('translate-left-button'); blink(e); e.click(); } | |
function moveRight() { e = el('translate-right-button'); blink(e); e.click(); } | |
function yawLeft() { e = el('yaw-left-button'); blink(e); e.click(); } | |
function yawRight() { e = el('yaw-right-button'); blink(e); e.click(); } | |
function pitchUp() { e = el('pitch-up-button'); blink(e); e.click(); } | |
function pitchDown() { e = el('pitch-down-button'); blink(e); e.click(); } | |
function rollLeft() { e = el('roll-left-button'); blink(e); e.click(); } | |
function rollRight() { e = el('roll-right-button'); blink(e); e.click(); } | |
// Artificial Intelligence | |
var a = 0.1; | |
var dt = 0.100; | |
var cnt = 0; | |
var hist = { | |
yaw: [0, 0, 0], | |
roll: [0, 0, 0], | |
pitch: [0, 0, 0], | |
y: [0, 0, 0], | |
z: [0, 0, 0], | |
r: [0, 0, 0] | |
}; | |
function AI(dt, x, v, a, finc, fdec) { | |
T = dt*Math.abs(v/a); | |
var target = x + v*T - 0.5*Math.sign(v)*a*T*T; | |
setTimeout(target < 0.0 ? finc : target > 0.0 ? fdec : ()=>{}, 0.8*Math.random()*dt*1000); | |
} | |
function v(x) { | |
var i = cnt - 3; if (i < 0) i += 3; var p0 = hist[x][i]; | |
var i = cnt - 1; if (i < 0) i += 3; var p2 = hist[x][i]; | |
return (p2 - p0)/(2*dt); | |
} | |
// Decision tree | |
function update() { | |
okYaw = Math.abs(getYaw(0)) < 2.0; | |
okRoll = Math.abs(getRoll(0)) < 2.0; | |
okPitch = Math.abs(getPitch(0)) < 2.0; | |
hist['yaw'][cnt] = getYaw(0); | |
hist['roll'][cnt] = getRoll(0); | |
hist['pitch'][cnt] = getPitch(0); | |
hist['y'][cnt] = getRangeY(0); | |
hist['z'][cnt] = getRangeZ(0); | |
hist['r'][cnt] = getRange() - 2.0; | |
if (++cnt > 2) cnt = 0; | |
if (okYaw && okRoll && okPitch) { | |
AI(dt, getRangeY(), v('y'), a, moveRight, moveLeft); | |
AI(dt, getRangeZ(), v('z'), a, moveUp, moveDown); | |
if (Math.abs(getRangeY() < 10.0) && Math.abs(getRangeZ() < 10.0)) { | |
if (getRange() > 2.0) { | |
AI(dt, getRange() - 2.0, v('r'), 0.5*a, moveBackward, moveForward); | |
} else { | |
if (getRate() < -0.15) { | |
moveBackward(); | |
} else if (getRate() > -0.05) { | |
moveForward(); | |
} | |
} | |
} | |
} | |
if (okYaw && okRoll && okPitch) { | |
AI(dt, getYaw(0), -getYaw(1), 0.2*a, yawLeft, yawRight); | |
AI(dt, getRoll(0), -getRoll(1), 0.2*a, rollLeft, rollRight); | |
AI(dt, getPitch(0), -getPitch(1), 0.2*a, pitchUp, pitchDown); | |
} else { | |
AI(dt, getYaw(0), v('yaw'), a, yawLeft, yawRight); | |
AI(dt, getRoll(0), v('roll'), a, rollLeft, rollRight); | |
AI(dt, getPitch(0), v('pitch'), a, pitchUp, pitchDown); | |
} | |
setTimeout(update, dt*1000); | |
} | |
update(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment