added state writing at configurable time steps

This commit is contained in:
Sakimori 2022-07-05 21:59:29 -04:00
parent 71845520b2
commit 92e9981eaf
5 changed files with 87 additions and 14 deletions

View file

@ -11,7 +11,7 @@
<OutputPath>.</OutputPath>
<Name>BoSLOO</Name>
<RootNamespace>BoSLOO</RootNamespace>
<InterpreterId>MSBuild|bosloo_env|$(MSBuildProjectFullPath)</InterpreterId>
<InterpreterId>MSBuild|BoSLOOenv|$(MSBuildProjectFullPath)</InterpreterId>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugSymbols>true</DebugSymbols>

View file

@ -1,12 +1,17 @@
import os, json, numpy, pygame, time, threading
import os, json, numpy, pygame, time, threading, jsonpickle
from renderer import *
from copy import deepcopy
groundControlPath = "GroundControlFiles"
groundControlPath = "GroundControl"
stateFilePath = os.path.join("SatState.json")
configPath = os.path.join("ConfigFiles", "OrbitSim")
configFilename = os.path.join(configPath, "Universe.cfg")
satSavePath = os.path.join(configPath, "Orbit.cfg")
mapFilename = os.path.join(configPath, "Map.png")
STATE_EVENT = pygame.event.custom_type()
def config():
"""Returns the config dictionary. Generates with default values if no config dictionary exists."""
@ -18,7 +23,8 @@ def config():
"G": 6.674e-11,
"earthMass": 5.972e24, #in kg
"earthRadius": 6378000, #meters
"timeScale": 1 #higher number go faster wheeeeee
"timeScale": 1, #higher number go faster wheeeeee
"updateTick": 300 #seconds to wait between save to file
}
with open(configFilename, "w") as file:
json.dump(config_dic, file, indent = 4)
@ -27,14 +33,67 @@ def config():
with open(configFilename) as file:
return json.load(file)
class OrbitingBody:
"""a zero-mass point object parented to a planet"""
def __init__(self, location:Point, velocity:Point, name, displaySize, parentPlanet):
self.location = location
self.resetLocation = location.copy()
self.velocity = velocity
self.resetVelocity = velocity.copy()
self.name = name
self.displaySize = displaySize #the size of the object on camera in pixels, for visibility reasons
self.parentPlanet = parentPlanet
self.lastDelta = 0
self.lastSecondDelta = 0
self.keepFreeze = 3
def stationKeep(self):
currDelta = Point.subtract(self.resetLocation, self.location).magnitude()
currSecondDelta = currDelta - self.lastDelta
if (currSecondDelta > 0) and (self.lastSecondDelta <= 0) and self.keepFreeze <= 0:
self.location = self.resetLocation.copy()
self.velocity = self.resetVelocity.copy()
self.keepFreeze = 3
elif self.keepFreeze > 0:
self.keepFreeze -= 1
self.lastDelta = currDelta
self.lastSecondDelta = currSecondDelta
def latLongAlt(self):
rho, theta, phi = self.location.polar()
rawLat, rawLong = self.parentPlanet.sphericalToLatLong(theta, phi) #negative lat is north, positive lat is south, positive long is east, negative long is west
return (rho - self.parentPlanet.radius), rawLat, rawLong
def writeStateReadable(self):
alt, lat, long = self.latLongAlt()
stateDic = {
"notes": "lat: pos S, neg N; long: pos E, neg W",
"latitude": lat,
"longitude": long,
"altitude": alt,
"velocity": self.velocity.magnitude()
}
with open(stateFilePath, "w") as file:
json.dump(stateDic, file, indent=4)
def saveState(self):
stateDic = {
"location": jsonpickle.encode(self.location),
"velocity": jsonpickle.encode(self.velocity),
}
def loadState(self):
if os.path.exists(satSavePath):
with open(satSavePath) as file:
state = json.load(file)
self.location = jsonpickle.decode(state["location"])
self.velocity = jsonpickle.decode(state["velocity"])
return True
else:
return False
class Planet:
"""A massive body at 0,0,0 and a given radius."""
@ -56,7 +115,7 @@ class Planet:
"""Converts theta and phi spherical coordinates to latitude and longitude. -> lat, long"""
rotRadian = self.rotationPercentage/100 * 2 * math.pi
lat = math.degrees(phi - (math.pi/2)) #negative lat is north, positive is south
long = theta - rotRadian #positive long is east, negative is west
long = rotRadian - theta #positive long is east, negative is west
if long < -math.pi:
long += math.pi*2
elif long > math.pi:
@ -97,6 +156,7 @@ def physicsUpdate(objects, orbitlines, deltaTime):
accel = Point.scalarMult(Point.subtract(obj.location, obj.parentPlanet.location).normalize(),-(config()["G"] * obj.parentPlanet.mass)/(Point.subtract(obj.location, obj.parentPlanet.location).magnitude() ** 2))
obj.velocity = Point.add(obj.velocity, Point.scalarMult(accel, deltaTime))
obj.location = Point.add(obj.location, Point.scalarMult(obj.velocity, deltaTime))
obj.stationKeep()
elif type(obj).__name__ == "Planet":
obj.rotate(deltaTime)
for line in orbitlines:
@ -116,10 +176,12 @@ if __name__=="__main__":
running = True
display = False
thisEarth = deepcopy(Planet.Earth)
sat = OrbitingBody(Point(0, config()["earthRadius"], config()["earthRadius"] - 800000), Point(-8900,0,0), "BoSLOO", 5, thisEarth)
sat = OrbitingBody(Point(0, config()["earthRadius"], config()["earthRadius"] - 800000), Point(-6900,0,0), "BoSLOO", 5, thisEarth)
orbitlines = []
renderObjects = [thisEarth, sat, orbitlines]
configFile = config()
clock = pygame.time.Clock()
stateTimer = pygame.time.set_timer(STATE_EVENT, configFile["updateTick"]*1000)
mapThread = threading.Thread()
save = False
@ -130,7 +192,7 @@ if __name__=="__main__":
clock.tick(FPS)
if display:
#deltaTime = frameTime * config()["timeScale"]
deltaTime = (clock.get_time()/1000) * config()["timeScale"]
deltaTime = (clock.get_time()/1000) * configFile["timeScale"]
physicsUpdate(renderObjects, orbitlines, deltaTime)
camera.renderFrame(save=save)
save=False
@ -142,7 +204,7 @@ if __name__=="__main__":
elif event.type == pygame.MOUSEBUTTONDOWN:
if not display:
display = True
camera = Camera(window, Point(10 * config()["earthRadius"], 0, 0), thisEarth, renderObjects)
camera = Camera(window, Point(10 * configFile["earthRadius"], 0, 0), thisEarth, renderObjects)
camera.renderFrame()
pygame.display.flip()
else:
@ -150,6 +212,10 @@ if __name__=="__main__":
if not mapThread.is_alive():
mapThread = threading.Thread(target=camera.saveGroundTrack())
mapThread.start()
elif event.type == STATE_EVENT:
sat.writeStateReadable()
configFile = config()
#time.sleep(frameTime)

7
SatState.json Normal file
View file

@ -0,0 +1,7 @@
{
"notes": "lat: pos S, neg N; long: pos E, neg W",
"latitude": -9.621613589753375,
"longitude": -135.404396876101,
"altitude": 2246794.2098555025,
"velocity": 6778.7033882673195
}

View file

@ -11,6 +11,9 @@ class Point:
def __init__(self, x, y, z):
self.vector = numpy.array([x, y, z])
def copy(self):
return Point(self.vector[0], self.vector[1], self.vector[2])
def polar(self):
"""Converts the vector rectangular coordinates to polar coordinates."""
if self.vector[0] == 0:
@ -28,7 +31,7 @@ class Point:
return [rho, theta, phi]
def magnitude(self):
return numpy.linalg.norm(self.vector)
return float(numpy.linalg.norm(self.vector))
def normalize(self):
self.vector = self.vector/self.magnitude()
@ -209,16 +212,13 @@ class Camera:
#pygame.draw.circle(screenSurface, (150,255,150), (int(intersectPoint.vector[1]), int(intersectPoint.vector[2])), 5)
#generate text
rho, theta, phi = sat.location.polar()
if rho < self.target.radius:
0 == 0
rawLat, rawLong = self.target.sphericalToLatLong(theta, phi)
alt, rawLat, rawLong = sat.latLongAlt()
self.updateTrackList(rawLat, rawLong)
latString = f"Latitude: {round(rawLat,4)}⁰ S" if rawLat >= 0 else f"Latitude: {-round(rawLat,4)}⁰ N"
longString = f"Longitude: {round(rawLong,4)}⁰ E" if rawLong >= 0 else f"Longitude: {-round(rawLong,4)}⁰ W"
font.render_to(backSurface, (0,0), f"Speed: {round(sat.velocity.magnitude()/1000,3)} km/s", (255,255,255))
font.render_to(backSurface, (0,20), f"Altitude: {round((rho - self.target.radius)/1000)} km", (255,255,255))
font.render_to(backSurface, (0,20), f"Altitude: {round((alt)/1000)} km", (255,255,255))
font.render_to(backSurface, (0,50), latString, (255,255,255))
font.render_to(backSurface, (0,70), longString, (255,255,255))

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 MiB

After

Width:  |  Height:  |  Size: 2.2 MiB