Getting Started with OOTK
Welcome to the Orbital Object Toolkit (OOTK)! This guide will help you get started with orbital mechanics programming, whether you're a beginner or an experienced developer new to this library.
Table of Contents
- What is OOTK?
- Installation
- Your First Satellite
- Understanding Coordinates
- Working with Sensors
- Common Use Cases
- Next Steps
What is OOTK?
OOTK (Orbital Object Toolkit) is a comprehensive library for orbital mechanics calculations in TypeScript/JavaScript. Think of it as your Swiss Army knife for:
- Tracking satellites from TLE data
- Predicting satellite passes over ground stations
- Converting between coordinate systems (latitude/longitude, ECI, ECF)
- Calculating orbital parameters (altitude, velocity, period)
- Determining orbits from observations
- Planning orbital maneuvers
Who is this for?
- Web developers building satellite tracking applications
- Researchers doing orbital mechanics analysis
- Students learning astrodynamics
- Hobbyists interested in space and satellites
What makes OOTK different?
- Type-safe: Uses TypeScript for catching errors at compile time
- Unit types: Prevents mixing degrees with radians, kilometers with meters
- Browser-friendly: Works in web browsers and Node.js
- Comprehensive: Everything from simple tracking to advanced orbit determination
Installation
Prerequisites
You'll need:
- Node.js (version 14 or higher)
- npm (comes with Node.js)
Install OOTK
npm install ootkVerify Installation
Create a test file test.js:
import { Earth } from 'ootk';
console.log('Earth radius:', Earth.radiusMean, 'km');Run it:
node test.jsYou should see: Earth radius: 6371 km
TypeScript Setup (Optional but Recommended)
If using TypeScript:
npm install --save-dev typescript @types/nodeCreate tsconfig.json:
{
"compilerOptions": {
"target": "ES2020",
"module": "ES2020",
"moduleResolution": "node",
"strict": true,
"esModuleInterop": true
}
}Your First Satellite
Let's track the International Space Station (ISS)!
Step 1: Get TLE Data
TLE (Two-Line Element) sets describe a satellite's orbit. You can get them from:
Example ISS TLE:
ISS (ZARYA)
1 25544U 98067A 24028.54545847 .00031576 00000-0 57240-3 0 9991
2 25544 51.6418 292.2590 0002595 167.5319 252.0460 15.49326324436741Step 2: Create a Satellite Object
import { Satellite, TleLine1, TleLine2 } from 'ootk';
// ISS TLE data
const tle1 = '1 25544U 98067A 24028.54545847 .00031576 00000-0 57240-3 0 9991' as TleLine1;
const tle2 = '2 25544 51.6418 292.2590 0002595 167.5319 252.0460 15.49326324436741' as TleLine2;
// Create satellite object
const iss = new Satellite({ tle1, tle2 });
console.log('ISS created successfully!');Step 3: Get Current Position
// Get position now
const eci = iss.eci();
console.log('Position (ECI):');
console.log(' X:', eci.position.x, 'km');
console.log(' Y:', eci.position.y, 'km');
console.log(' Z:', eci.position.z, 'km');
console.log('Velocity (ECI):');
console.log(' X:', eci.velocity.x, 'km/s');
console.log(' Y:', eci.velocity.y, 'km/s');
console.log(' Z:', eci.velocity.z, 'km/s');Output Example:
Position (ECI):
X: 3590.123 km
Y: -5234.789 km
Z: 2100.456 km
Velocity (ECI):
X: 4.567 km/s
Y: 3.210 km/s
Z: 5.432 km/sStep 4: Get Latitude/Longitude
const lla = iss.lla();
console.log('Latitude:', lla.lat, '°');
console.log('Longitude:', lla.lon, '°');
console.log('Altitude:', lla.alt, 'km');Output Example:
Latitude: 23.456 °
Longitude: -45.678 °
Altitude: 418.234 kmStep 5: Get Orbital Parameters
console.log('Orbital Parameters:');
console.log(' Inclination:', iss.inclination, '°');
console.log(' Eccentricity:', iss.eccentricity);
console.log(' Period:', iss.period, 'minutes');
console.log(' Apogee:', iss.apogee, 'km');
console.log(' Perigee:', iss.perigee, 'km');Congratulations! You've just tracked your first satellite with OOTK!
Understanding Coordinates
OOTK uses several coordinate systems. Here's a simple explanation:
1. Geodetic (Latitude/Longitude/Altitude)
What: The coordinates you're familiar with from maps.
When to use: Displaying positions on a map, human-readable locations.
const lla = iss.lla();
// { lat: 23.456°, lon: -45.678°, alt: 418 km }2. ECI (Earth-Centered Inertial)
What: X, Y, Z coordinates in a non-rotating reference frame.
When to use: Physics calculations, propagating orbits.
const eci = iss.eci();
// { position: {x, y, z}, velocity: {x, y, z} }3. ECF (Earth-Centered Fixed)
What: X, Y, Z coordinates that rotate with Earth.
When to use: Ground station calculations, terrain modeling.
const ecf = iss.ecf();
// { position: {x, y, z}, velocity: {x, y, z} }Quick Conversions
// Satellite gives you all of them:
const lla = satellite.lla(); // Geodetic
const eci = satellite.eci(); // ECI
const ecf = satellite.ecf(); // ECF
const j2000 = satellite.toJ2000(); // J2000 (specific ECI frame)Working with Sensors
A "sensor" in OOTK is a ground station or observation point that tracks satellites.
Create a Sensor
Let's create a sensor for Cape Cod:
import { Sensor, Degrees, Kilometers } from 'ootk';
const capeCod = new Sensor({
lat: 41.754785 as Degrees,
lon: -70.539151 as Degrees,
alt: 0.060966 as Kilometers,
minEl: 5 as Degrees, // Don't track below 5° elevation
maxEl: 85 as Degrees, // Don't track above 85°
minRng: 0 as Kilometers,
maxRng: 5000 as Kilometers // Maximum tracking range
});Note: The as Degrees and as Kilometers are TypeScript type casts that ensure you're using the right units.
Calculate Look Angles
Get Range, Azimuth, Elevation from sensor to satellite:
const rae = capeCod.rae(iss);
console.log('Range:', rae.rng, 'km');
console.log('Azimuth:', rae.az, '° (0=North, 90=East)');
console.log('Elevation:', rae.el, '° (0=horizon, 90=zenith)');
console.log('Range Rate:', rae.rngRate, 'km/s');Interpretation:
- Range: Distance to satellite
- Azimuth: Which direction to point (compass heading)
- Elevation: How high to look up
- Range Rate: How fast distance is changing (negative = approaching)
Check Visibility
const isVisible = capeCod.isSatInFov(iss);
if (isVisible) {
console.log('ISS is currently visible from Cape Cod!');
const rae = capeCod.rae(iss);
console.log('Look', rae.az.toFixed(1), '° at', rae.el.toFixed(1), '° elevation');
} else {
console.log('ISS is not visible right now.');
}Predict Passes
Find when satellite will be visible:
// Calculate passes over next 24 hours, checking every 10 seconds
const passes = capeCod.calculatePasses(10, iss, {
startDate: new Date(),
lengthDays: 1
});
console.log(`Found ${passes.length} passes in the next 24 hours:`);
passes.forEach((pass, index) => {
console.log(`\nPass ${index + 1}:`);
console.log(' Rise:', pass.rise.toLocaleString());
console.log(' Peak:', pass.culmination.toLocaleString());
console.log(' Set:', pass.set.toLocaleString());
console.log(' Max Elevation:', pass.maxEl.toFixed(1), '°');
console.log(' Duration:', (pass.duration / 60).toFixed(1), 'minutes');
});Output Example:
Found 3 passes in the next 24 hours:
Pass 1:
Rise: 1/28/2024, 6:23:45 PM
Peak: 1/28/2024, 6:28:12 PM
Set: 1/28/2024, 6:32:51 PM
Max Elevation: 45.3 °
Duration: 9.1 minutes
Pass 2:
Rise: 1/28/2024, 8:01:23 PM
Peak: 1/28/2024, 8:05:45 PM
Set: 1/28/2024, 8:10:12 PM
Max Elevation: 78.6 °
Duration: 8.8 minutes
...Common Use Cases
1. Real-Time Satellite Tracker
import { Satellite, TleLine1, TleLine2 } from 'ootk';
class SatelliteTracker {
private satellite: Satellite;
constructor(tle1: TleLine1, tle2: TleLine2) {
this.satellite = new Satellite({ tle1, tle2 });
}
getCurrentPosition() {
const lla = this.satellite.lla();
return {
latitude: lla.lat,
longitude: lla.lon,
altitude: lla.alt
};
}
getVelocity() {
const eci = this.satellite.eci();
const speed = Math.sqrt(
eci.velocity.x ** 2 +
eci.velocity.y ** 2 +
eci.velocity.z ** 2
);
return speed; // km/s
}
}
// Usage
const tracker = new SatelliteTracker(tle1, tle2);
setInterval(() => {
const pos = tracker.getCurrentPosition();
const speed = tracker.getVelocity();
console.log(
`Lat: ${pos.latitude.toFixed(2)}°, ` +
`Lon: ${pos.longitude.toFixed(2)}°, ` +
`Alt: ${pos.altitude.toFixed(1)} km, ` +
`Speed: ${speed.toFixed(2)} km/s`
);
}, 1000); // Update every second2. Ground Station Pass Predictor
import { Sensor, Satellite, Degrees, Kilometers } from 'ootk';
function predictPasses(
sensorLat: number,
sensorLon: number,
sensorAlt: number,
tle1: TleLine1,
tle2: TleLine2,
days: number = 7
) {
const sensor = new Sensor({
lat: sensorLat as Degrees,
lon: sensorLon as Degrees,
alt: sensorAlt as Kilometers,
minEl: 10 as Degrees, // Only show passes above 10°
maxEl: 90 as Degrees,
minRng: 0 as Kilometers,
maxRng: 5000 as Kilometers
});
const satellite = new Satellite({ tle1, tle2 });
const passes = sensor.calculatePasses(30, satellite, {
startDate: new Date(),
lengthDays: days
});
return passes.map(pass => ({
riseTime: pass.rise,
setTime: pass.set,
peakTime: pass.culmination,
maxElevation: pass.maxEl,
durationMinutes: pass.duration / 60
}));
}
// Usage
const myPasses = predictPasses(
40.7128, // New York City latitude
-74.0060, // longitude
0.010, // altitude (km)
isstle1,
isstle2,
7 // next 7 days
);
console.log('Upcoming passes:', myPasses);3. Multi-Satellite Tracker
class MultiSatelliteTracker {
private satellites: Map<string, Satellite> = new Map();
addSatellite(name: string, tle1: TleLine1, tle2: TleLine2) {
this.satellites.set(name, new Satellite({ tle1, tle2 }));
}
getAllPositions() {
const positions = {};
this.satellites.forEach((sat, name) => {
const lla = sat.lla();
positions[name] = {
lat: lla.lat,
lon: lla.lon,
alt: lla.alt
};
});
return positions;
}
findVisible(sensorLat: number, sensorLon: number) {
const sensor = new Sensor({
lat: sensorLat as Degrees,
lon: sensorLon as Degrees,
alt: 0 as Kilometers,
minEl: 5 as Degrees,
maxEl: 85 as Degrees,
minRng: 0 as Kilometers,
maxRng: 5000 as Kilometers
});
const visible = [];
this.satellites.forEach((sat, name) => {
if (sensor.isSatInFov(sat)) {
const rae = sensor.rae(sat);
visible.push({
name,
azimuth: rae.az,
elevation: rae.el,
range: rae.rng
});
}
});
return visible;
}
}
// Usage
const tracker = new MultiSatelliteTracker();
tracker.addSatellite('ISS', isstle1, isstle2);
tracker.addSatellite('HUBBLE', hubbleTle1, hubbleTle2);
tracker.addSatellite('GPS-1', gpsTle1, gpsTle2);
// Get all positions
const allPositions = tracker.getAllPositions();
console.log(allPositions);
// Find what's visible from your location
const visibleSats = tracker.findVisible(40.7128, -74.0060);
console.log('Currently visible:', visibleSats);4. Satellite Position at Specific Time
import { Satellite, EpochUTC } from 'ootk';
const satellite = new Satellite({ tle1, tle2 });
// Position at a specific time
const specificDate = new Date('2024-12-31T00:00:00Z');
const eci = satellite.eci(specificDate);
const lla = satellite.lla(specificDate);
console.log('Position on New Year 2024:');
console.log(' Lat:', lla.lat, '°');
console.log(' Lon:', lla.lon, '°');
console.log(' Alt:', lla.alt, 'km');5. Calculate Orbit Period
function analyzeSatellite(tle1: TleLine1, tle2: TleLine2) {
const sat = new Satellite({ tle1, tle2 });
console.log('Orbital Analysis:');
console.log(' Period:', sat.period.toFixed(2), 'minutes');
console.log(' Apogee:', sat.apogee.toFixed(1), 'km');
console.log(' Perigee:', sat.perigee.toFixed(1), 'km');
console.log(' Inclination:', sat.inclination.toFixed(2), '°');
console.log(' Eccentricity:', sat.eccentricity.toFixed(6));
// Classify orbit
const avgAlt = (sat.apogee + sat.perigee) / 2;
let orbitType;
if (avgAlt < 2000) orbitType = 'LEO (Low Earth Orbit)';
else if (avgAlt < 35786) orbitType = 'MEO (Medium Earth Orbit)';
else if (Math.abs(avgAlt - 35786) < 100) orbitType = 'GEO (Geostationary)';
else orbitType = 'HEO (High Earth Orbit)';
console.log(' Classification:', orbitType);
// Orbits per day
const orbitsPerDay = (24 * 60) / sat.period;
console.log(' Orbits per day:', orbitsPerDay.toFixed(2));
}
analyzeSatellite(isstle1, isstle2);Next Steps
Beginner Level
Now that you understand the basics:
- Try different satellites: Get TLEs from https://celestrak.org/
- Change sensor locations: Track from your city
- Experiment with times: Look at positions in the past or future
- Build a web interface: Display positions on a map
Intermediate Level
Ready for more? Explore:
- Different propagators: Try
RungeKutta4Propagatorfor higher accuracy - Coordinate transformations: Convert between J2000, TEME, ITRF
- Time systems: Work with UTC, GPS time, Julian dates
- Force models: Add gravity harmonics, drag, solar radiation pressure
See the User Guide sections:
Advanced Level
For advanced orbital mechanics:
- Initial Orbit Determination: Determine orbits from observations
- Maneuver Planning: Calculate delta-v for orbit changes
- Covariance Propagation: Track uncertainty in orbits
- Custom Propagators: Create your own propagation methods
See the User Guide sections:
Troubleshooting
Common Issues
1. "Cannot find module 'ootk'"
Problem: Import error
Solution: Make sure you've installed OOTK:
npm install ootkAnd that your package.json has "type": "module" for ES modules.
2. Type errors with numbers
Problem: TypeScript complains about number types
Solution: Cast to appropriate types:
// Wrong
const lat = 41.7;
// Correct
const lat = 41.7 as Degrees;3. Satellite position seems wrong
Problem: Position doesn't match expected values
Solutions:
- Check TLE is current (TLEs expire quickly, especially for LEO)
- Verify the time (use
new Date()for current time) - Ensure TLE lines are correct (no extra spaces or truncation)
4. No passes found
Problem: calculatePasses() returns empty array
Solutions:
- Increase
lengthDaysparameter (satellite may not pass for several days) - Lower
minElon sensor (try 0 degrees) - Increase
maxRngon sensor - Check satellite orbit (geostationary satellites don't "pass")
Getting Help
- Documentation: See User Guide
- Examples: Check
/examplesfolder in repository - Issues: https://github.com/thkruz/ootk/issues
- Discussions: https://github.com/thkruz/ootk/discussions
Quick Reference
Essential Imports
// Basic tracking
import { Satellite, TleLine1, TleLine2 } from 'ootk';
// Sensors
import { Sensor, Degrees, Kilometers } from 'ootk';
// Advanced
import {
Satellite,
Sensor,
EpochUTC,
J2000,
ClassicalElements,
RungeKutta4Propagator,
ForceModel
} from 'ootk';Common Patterns
// Create satellite
const sat = new Satellite({ tle1, tle2 });
// Get position now
const lla = sat.lla();
const eci = sat.eci();
// Get position at specific time
const date = new Date('2024-12-31T00:00:00Z');
const llaFuture = sat.lla(date);
// Create sensor
const sensor = new Sensor({
lat: latitude as Degrees,
lon: longitude as Degrees,
alt: altitude as Kilometers,
minEl: 5 as Degrees,
maxEl: 85 as Degrees,
minRng: 0 as Kilometers,
maxRng: 5000 as Kilometers
});
// Check visibility
const visible = sensor.isSatInFov(sat);
// Get look angles
const rae = sensor.rae(sat);
// Find passes
const passes = sensor.calculatePasses(30, sat, {
startDate: new Date(),
lengthDays: 7
});Example Projects to Build
1. ISS Notifier
Build a program that alerts you when the ISS will pass overhead.
Skills: Satellite tracking, pass prediction, notifications
2. Satellite Constellation Visualizer
Display multiple satellites on a map in real-time.
Skills: Multi-satellite tracking, web development, visualization
3. Ground Station Planner
Determine the best location for a ground station to maximize satellite contact time.
Skills: Sensor placement, pass analysis, optimization
4. Orbit Comparator
Compare different satellites' orbits and find close approaches.
Skills: Coordinate transformations, distance calculations
5. TLE Age Checker
Monitor a catalog of TLEs and alert when they're getting old.
Skills: TLE parsing, date handling, automation
Resources
Where to Get TLE Data
- CelesTrak: https://celestrak.org/ (free, no account needed)
- Space-Track: https://www.space-track.org/ (free account required)
- KeepTrack API: https://api.keeptrack.space/ (simple REST API)
Learning More
- Orbital Mechanics: "Fundamentals of Astrodynamics" by Bate, Mueller, White
- SGP4: "Revisiting Spacetrack Report #3" by Vallado et al.
- OOTK Repository: https://github.com/thkruz/ootk
- Full Documentation: User Guide
Related Projects
- KeepTrack: https://github.com/thkruz/keeptrack.space
- satellite.js: Alternative JavaScript satellite library
- Skyfield: Python satellite library
Congratulations
You're now ready to start building with OOTK. Start simple with satellite tracking, then explore more advanced features as you need them.
Happy coding!
If you build something cool with OOTK, consider sharing it with the community!
License: AGPL-3.0
Version: 5.1.1
Last Updated: January 2024