James Webb Space Telescope

On Christmas morning, I was watching the launch of the JWST. As they talked about it, they said it would orbit at the L2 Lagrange point to stay at a position opposite the Sun from the Earth. I looked up the info on it, but I wasn’t sure why it would stay at that point. I got my 3 body orbit program and figured I’d see if it could do the same thing. So I set the initial values to position the Sun, Earth, and the JWST. It took quite awhile of altering the values of the JWST, but I finally got it to orbit for about 2.5 Earth orbits before it became unstable and went off on its own. After watching it, I could see what was really happening. The JWST was at an orbit position so that it took about one year to orbit the Earth. Since the Earth took one year to orbit the Sun, the JWST would remain in the same position relative to the Sun Earth line, keeping it opposite the Sun.

So here’s the program. It only works for about 2.5 Earth orbits before it goes unstable because of the accuracy of the calculations and scale. If you uncomment the code at the end, that shows the same thing but with just a simple sin cos calculation of points revolving around in a circle.

viewer.mode=FULLSCREEN

function setup()    
    xx=0
    yy=0
    
    -- object 1
    gs1 = 1000          -- gravity of object 1
    xs1 = WIDTH/2       -- start x position
    ys1 = HEIGHT/2      -- start y position
    dxs1 = 0            -- initial change in x position
    dys1 = 0            -- initial change in y position
    
    -- object 2 
    gs2 = 10            -- gravity of object 2
    xs2 = WIDTH/2       -- start x position
    ys2 = HEIGHT/2+200  -- start y position
    dxs2 = -2.236       -- initial change in x position
    dys2 = 0            -- initial change in y position
    
    -- object 3
    gs3 = 0                     -- gravity of object 3
    xs3 = WIDTH/2               -- start x position
    ys3 = HEIGHT/2+230          -- start y position
    dxs3 = -2.6475032398507     -- initial change in x position
    dys3 = 0                    -- initial change in y position 
end

function draw()
    background(0)
    
    -- gravity object 2  to object 1
    d = gs2 / math.pow(( (xs1 - xs2) * (xs1 - xs2) + (ys1 - ys2) * (ys1 - ys2) ), 1.5 )
    dxs1 = dxs1 - (( xs1 - xs2 ) * d)
    dys1 = dys1 - (( ys1 - ys2 ) * d)
    
    -- gravity object 1  to object 2
    d = gs1 / math.pow(( (xs2 - xs1) * (xs2 - xs1) + (ys2 - ys1) * (ys2 - ys1) ), 1.5 )
    dxs2 = dxs2 - (( xs2 - xs1 ) * d)
    dys2 = dys2 - (( ys2 - ys1 ) * d)
        
    -- gravity object 2  to object 3
    d = gs2 / math.pow(( (xs3 - xs2) * (xs3 - xs2) + (ys3 - ys2) * (ys3 - ys2) ), 1.5 )
    dxs3 = dxs3 - (( xs3 - xs2 ) * d)
    dys3 = dys3 - (( ys3 - ys2 ) * d)
    
    -- gravity object 3  to object 2
    d = gs3 / math.pow(( (xs2 - xs3) * (xs2 - xs3) + (ys2 - ys3) * (ys2 - ys3) ), 1.5 )
    dxs2 = dxs2 - (( xs2 - xs3 ) * d)
    dys2 = dys2 - (( ys2 - ys3 ) * d)
    
    -- gravity object 1  to object 3
    d = gs1 / math.pow(( (xs3 - xs1) * (xs3 - xs1) + (ys3 - ys1) * (ys3 - ys1) ), 1.5 )
    dxs3 = dxs3 - (( xs3 - xs1 ) * d)
    dys3 = dys3 - (( ys3 - ys1 ) * d)
    
    -- gravity object 3  to object 1
    d = gs3 / math.pow(( (xs1 - xs3) * (xs1 - xs3) + (ys1 - ys3) * (ys1 - ys3) ), 1.5 )
    dxs1 = dxs1 - (( xs1 - xs3 ) * d)
    dys1 = dys1 - (( ys1 - ys3 ) * d)
        
    xs1 = xs1 + dxs1
    ys1 = ys1 + dys1
    xs2 = xs2 + dxs2
    ys2 = ys2 + dys2
    xs3 = xs3 + dxs3
    ys3 = ys3 + dys3
        
    fill(255, 255, 0)   
    ellipse(xs1-xx,ys1-yy,25)
    fill(0,255,0)
    ellipse(xs2-xx,ys2-yy,10)   
    fill(255)
    ellipse(xs3-xx,ys3-yy,5)    
end

--[[
function setup()
    ang=0
end

function draw()
    background(0)
    fill(255, 255, 0)   
    ellipse(WIDTH/2,HEIGHT/2,25)
    fill(0,255,0)
    x=math.cos(math.rad(ang))*200
    y=math.sin(math.rad(ang))*200
    ellipse(WIDTH/2+x,HEIGHT/2+y,10)   
    fill(255)
    x=math.cos(math.rad(ang))*230
    y=math.sin(math.rad(ang))*230
    ellipse(WIDTH/2+x,HEIGHT/2+y,5)   
    ang=ang+1
end
--]]

Nice. It turns out that Lagrange point isn’t stable, as are L4 and L4, just “meta stable”, which means you need some thrust adjustments to stay there.

Did you watch the film about Katherine Johnson/Coleman who calculated the safe trajectories of the early US manned space flights before computers. Awesome minds, don’t think iPad and Codea could compete.

On space issues - just watching ‘Don’t look up’ about a meteor trajectory. Shows how much calculations of space entities have changed since her time !!! - well not really it’s only fantasy, besides we’ve got our good old friend Jupiter to help us.

@Bri_G I saw ads for the film, but didn’t see the film itself. Looked interesting. I’ll have to keep an eye out for it just in case it comes around again.

@Bri_G I just watched Don’t Look Up, I liked it. The running joke about the four star general charging for snacks was pretty good

@Simeon - yeah, lots of digs in. Did you recognize the white haired entrepreneur ? Final part with the Garden of Eden with naked humans joke was funny, if a bit predictable.

@dave1707 that is such a cool project. In looking into this I found an interesting post on decoding the JWST telemetry data https://destevez.net/2021/12/decoding-james-webb-space-telescope/

Edit: I liked seeing the JWST get unstable and start orbiting the sun after some time

@Simeon I just hope the JWST goes thru all of it unfolding steps successfully so there isn’t 10 billion dollars worth of junk up there.

I spent a lot of time altering the velocity to get it to last that long. I guess there was just too much rounding in all the calculations to get it to last longer. I have another program with 3 objects orbiting each other. That one eventually has one object fly off the screen. In that program, I can tap the screen so each object leaves a trail as they orbit. It creates an intricate design as they interact with each other.

This is really awesome and another example of the kind of next-level smarts going on around here.

Any chance you could make it in Craft? :wink:

@UberGoober Not sure what doing it in Craft would add to it. It doesn’t run that long and the whole point is just to show that the JWST orbits the Earth staying opposite the Sun. It wasn’t until I was watching this that I realized that the JWST was in a 1 year orbit around the Earth staying opposite the Sun.

@dave1707 it would just be cool to move around it with OrbitViewer, that’s all. Nbd.

@UberGoober That might be interesting, I’ll give it a try.

@UberGoober Here’s a Craft version. I don’t think it was worth the effort. I got less than 2 Earth orbits before it became unstable. I could have worked with it more to increase the stability, but it’s enough to see what’s happening.

viewer.mode=FULLSCREEN

function setup()
    scene = craft.scene()
    scene.physics.gravity=vec3(0,0,0)
    createObjects()
    v=scene.camera:add(OrbitViewer, vec3(0,0,0), 200, 0, 1000)
end

function createObjects()    
    gs1 = 1             -- gravity of object 1
    xs1 = 0             -- start x position
    ys1 = 0             -- start y position
    dxs1 = 0            -- initial change in x position
    dys1 = 0            -- initial change in y position
    
    gs2 = .02           -- gravity of object 2
    xs2 = 0             -- start x position
    ys2 = 20            -- start y position
    dxs2 = .23          -- initial change in x position
    dys2 = 0            -- initial change in y position
    
    gs3 = 0             -- gravity of object 3
    xs3 = 0             -- start x position
    ys3 = 24            -- start y position
    dxs3 = .27443192008 -- initial change in x position
    dys3 = 0            -- initial change in y position 
    
    sun=scene:entity()
    s1=sun:add(craft.rigidbody,KINEMATIC)
    sun.position=vec3(0,0,0)
    sun:add(craft.shape.sphere,2)
    sun.model = craft.model.icosphere(2,2)
    sun.material = craft.material(asset.builtin.Materials.Specular)
    sun.material.diffuse=color(241, 255, 0)
    
    earth=scene:entity()
    e1=earth:add(craft.rigidbody,KINEMATIC)
    earth.position=vec3(0,10,0)
    earth:add(craft.shape.sphere,.5)
    earth.model = craft.model.icosphere(.5,2)
    earth.material = craft.material(asset.builtin.Materials.Specular)
    earth.material.diffuse=color(29, 255, 0)
    
    jwst=scene:entity()
    j1=jwst:add(craft.rigidbody,KINEMATIC)
    jwst.position=vec3(0,11,0)
    jwst:add(craft.shape.sphere,.3)
    jwst.model = craft.model.icosphere(.3,2)
    jwst.material = craft.material(asset.builtin.Materials.Specular)
    jwst.material.diffuse=color(255)
end

function draw()
    update(DeltaTime)
    scene:draw() 
    -- gravity object 2  to object 1
    d = gs2 / math.pow(( (xs1 - xs2) * (xs1 - xs2) + (ys1 - ys2) * (ys1 - ys2) ), 1.5 )
    dxs1 = dxs1 - (( xs1 - xs2 ) * d)
    dys1 = dys1 - (( ys1 - ys2 ) * d)
    
    -- gravity object 1  to object 2
    d = gs1 / math.pow(( (xs2 - xs1) * (xs2 - xs1) + (ys2 - ys1) * (ys2 - ys1) ), 1.5 )
    dxs2 = dxs2 - (( xs2 - xs1 ) * d)
    dys2 = dys2 - (( ys2 - ys1 ) * d)
    
    -- gravity object 2  to object 3
    d = gs2 / math.pow(( (xs3 - xs2) * (xs3 - xs2) + (ys3 - ys2) * (ys3 - ys2) ), 1.5 )
    dxs3 = dxs3 - (( xs3 - xs2 ) * d)
    dys3 = dys3 - (( ys3 - ys2 ) * d)
    
    -- gravity object 3  to object 2
    d = gs3 / math.pow(( (xs2 - xs3) * (xs2 - xs3) + (ys2 - ys3) * (ys2 - ys3) ), 1.5 )
    dxs2 = dxs2 - (( xs2 - xs3 ) * d)
    dys2 = dys2 - (( ys2 - ys3 ) * d)
    
    -- gravity object 1  to object 3
    d = gs1 / math.pow(( (xs3 - xs1) * (xs3 - xs1) + (ys3 - ys1) * (ys3 - ys1) ), 1.5 )
    dxs3 = dxs3 - (( xs3 - xs1 ) * d)
    dys3 = dys3 - (( ys3 - ys1 ) * d)
    
    -- gravity object 3  to object 1
    d = gs3 / math.pow(( (xs1 - xs3) * (xs1 - xs3) + (ys1 - ys3) * (ys1 - ys3) ), 1.5 )
    dxs1 = dxs1 - (( xs1 - xs3 ) * d)
    dys1 = dys1 - (( ys1 - ys3 ) * d)
    
    xs1 = xs1 + dxs1
    ys1 = ys1 + dys1
    xs2 = xs2 + dxs2
    ys2 = ys2 + dys2
    xs3 = xs3 + dxs3
    ys3 = ys3 + dys3  
    
    sun.position=vec3(xs1,ys1,0)
    earth.position=vec3(xs2,ys2,0)
    jwst.position=vec3(xs3,ys3,0)
end

function update(dt)
    scene:update(dt)
end

Im sorry it didn’t feel worth it. On my end it’s much more fun to watch. But I understand the point was to model the calculations, not make something visually interesting.

@UberGoober You could make false orbits. Just have a bunch of spheres going around a Sun at different distances using sin and cos to calculate circular positions. That should give you the same effect unless you’re after the uncertainty of the orbit after awhile.

@UberGoober Here’s another version if you thought it was fun to watch. I also shrunk the code.

viewer.mode=FULLSCREEN

function setup()
    obj,tab={},{}
    scene = craft.scene()
    scene.physics.gravity=vec3(0,0,0)
    v=scene.camera:add(OrbitViewer, vec3(0,0,0), 150, 0, 1000)
    
    createObjects(2,color(255, 255, 0))
    createObjects(1,color(0, 255, 0))
    createObjects(1,color(255, 0, 181))
    createObjects(1,color(255,0,0))
    createObjects(1,color(0, 58, 255))
    
    table.insert(obj,{gr=1,x=0,y=0,dx=0,dy=0})    
    table.insert(obj,{gr=.02,x=0,y=20,dx=.23,dy=0})
    table.insert(obj,{gr=0,x=0,y=27,dx=.09,dy=0})
    table.insert(obj,{gr=0,x=0,y=33,dx=.15,dy=0})
    table.insert(obj,{gr=0,x=10,y=33,dx=.12,dy=0})
end

function createObjects(s,c)    
    local temp=scene:entity()
    local s1=temp:add(craft.rigidbody,KINEMATIC)
    temp.position=vec3(0,0,0)
    temp:add(craft.shape.sphere,s)
    temp.model = craft.model.icosphere(s,2)
    temp.material = craft.material(asset.builtin.Materials.Specular)
    temp.material.diffuse=c
    table.insert(tab,temp)
end

function draw()
    update(DeltaTime)
    scene:draw() 
    
    for z=1,#obj-1 do
        for w=z+1,#obj do
            d=obj[z].gr/math.pow(((obj[w].x-obj[z].x)*(obj[w].x-obj[z].x)+
                    (obj[w].y-obj[z].y)*(obj[w].y-obj[z].y)),1.5)
            obj[w].dx=obj[w].dx-((obj[w].x-obj[z].x)*d)
            obj[w].dy=obj[w].dy-((obj[w].y-obj[z].y)*d)
            
            d=obj[w].gr/math.pow(((obj[z].x-obj[w].x)*(obj[z].x-obj[w].x)+
                    (obj[z].y-obj[w].y)*(obj[z].y-obj[w].y)), 1.5)
            obj[z].dx=obj[z].dx-((obj[z].x-obj[w].x)*d)
            obj[z].dy=obj[z].dy-((obj[z].y-obj[w].y)*d)
        end
    end
    for a,b in pairs(obj) do
        b.x=b.x+b.dx
        b.y=b.y+b.dy
        tab[a].position=vec3(b.x,b.y,0)       
    end  
end

function update(dt)
    scene:update(dt)
end

Why doesn’t text selection work correctly on this website anymore? How is a website even affecting that—isn’t it a native iOS function? Very weird.