Skip to content

Commit

Permalink
Add files via upload
Browse files Browse the repository at this point in the history
-AATC now supports using the Open Weather Map service to lookup the weather at a given coordinate for a flight in order to make ajustments to the estimated flight time. Two settings can be used: 1. Estimate speed from start and end coordinate. 2. Estimate speed from each pair of coordinates.
1. This is less accurate for waypoint ETA, however it requires fewer requests and will be similarly accurate for total ETA. (Default)
2. This method queries the wind speed for each set of coordinates. The program will take longer to run due to multiple requests and must sleep between requests in order to not exceed the request limit.
  • Loading branch information
Scratchcat1 authored Nov 26, 2017
1 parent 63f0e68 commit 20164b3
Show file tree
Hide file tree
Showing 10 changed files with 137 additions and 43 deletions.
2 changes: 1 addition & 1 deletion AATC_Client.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ def AddUser(self,Username,Password):
return Sucess,Message

def SetFlightVisibility(self,Visibility):
self.Send("SetUserPublicVisibleFlights",(Visibility,))
self.Send("SetFlightVisibility",(Visibility,))
Sucess,Message,_ = self.Recv()
return Sucess,Message

Expand Down
4 changes: 3 additions & 1 deletion AATC_Config.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,6 @@
#Control at which setting the server will raise an error if the cost for entering that node sector exceeds value. To prevent selecting a blocked node as a target node to bypass search algorithm.
NOFLYZONE_THRESHOLD_COST = 50


#OWM Controls
ENABLE_FINE_SPEED_ESTIMATION = False #Allows fine grained estimation of drone speed due to wind. Noticable slowdown when creating flight due to many requests which may be limited by OWM depending on contract
OWM_SLEEP_TIME = 1/60*60*4 # How long the add flight program should sleep between requests to reduce the chance of overusing requests. 1/REQUESTS_PER_MINUTE*60*NUMBER_OF_CONCURRENT_SEARCHES should ensure that the program never hits the limit of OWM.
12 changes: 12 additions & 0 deletions AATC_Coordinate.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,3 +115,15 @@ def DeltaCoordToMetres(aCoord,bCoord):

Distance = math.sqrt(mdx**2 + mdy**2 + dz**2)
return Distance


def GetBearing(Coord1,Coord2):
dy = Coord2.Get_Y()-Coord1.Get_Y()
dx = math.cos(math.pi/180 * Coord1.Get_Y())*(Coord2.Get_X()-Coord1.Get_X())
angle = (360+90-(math.atan2(dy,dx)*180/math.pi))%360
return angle

def Reverse_Angle(deg):
return (180+deg)%360


13 changes: 11 additions & 2 deletions AATC_DB.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ def CheckCredentials(self,Username,Password):
else:
return False,"Incorrect Credentials",-1

def SetUserPublicVisibleFlights(self,UserID,Value):
def SetFlightVisibility(self,UserID,Value):
if Value in [0,1]:
self.cur.execute("UPDATE User SET PublicVisibleFlights = %s WHERE UserID = %s",(Value,UserID))
self.db_con.commit()
Expand Down Expand Up @@ -197,7 +197,7 @@ def GetFlightsAll(self):
def AddFlight(self,UserID,DroneID,StartCoords,EndCoords,StartTime,ETA,EndTime,Distance,XOffset,YOffset,ZOffset):
self.cur.execute("SELECT 1 FROM User,Drone WHERE Drone.DroneID = %s AND Drone.UserID = %s",(DroneID,UserID))
if self.cur.fetchall() !=():
self.cur.execute("INSERT INTO Flight(DroneID,StartCoords,EndCoords,StartTime,ETA,EndTime,Distance,XOffset,YOffset,ZOffset,Completed) VALUES(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,0)",(DroneID,str(StartCoords),str(EndCoords),int(StartTime),int(ETA),int(EndTime),Distance,XOffset,YOffset,ZOffset))
self.cur.execute("INSERT INTO Flight(DroneID,StartCoords,EndCoords,StartTime,ETA,EndTime,Distance,XOffset,YOffset,ZOffset,Completed) VALUES(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,0)",(DroneID,str(StartCoords),str(EndCoords),int(StartTime),int(ETA),int(EndTime),int(Distance),XOffset,YOffset,ZOffset))
self.db_con.commit()
return True,"Flight added"
else:
Expand Down Expand Up @@ -270,6 +270,15 @@ def AddWaypoint(self,UserID,FlightID,WaypointNumber,Coords,ETA,BlockTime=0):
return True,"Added Waypoint"
else:
return False,"You do not have permission to add a waypoint for this flight"

def AddWaypoints(self,UserID,FlightID,Waypoints):
self.cur.execute("SELECT 1 FROM User,Flight,Drone WHERE User.UserID = %s AND User.UserID = Drone.UserID AND Drone.DroneID = Flight.DroneID AND Flight.FlightID = %s",(UserID,FlightID))
if self.cur.fetchall() !=():
self.cur.executemany("INSERT INTO FlightWaypoints(FlightID,WaypointNumber,Coords,ETA,BlockTime) VALUES(%s,%s,%s,%s,%s)",Waypoints)
self.db_con.commit()
return True,"Added Waypoints"
else:
return False,"You do not have permission to add a waypoint for this flight"

def RemoveFlightWaypoints(self,UserID,FlightID):
self.cur.execute("SELECT 1 FROM User,Flight,Drone WHERE User.UserID = %s AND User.UserID = Drone.UserID AND Drone.DroneID = Flight.DroneID AND Flight.FlightID = %s",(UserID,FlightID))
Expand Down
2 changes: 1 addition & 1 deletion AATC_GPIO.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
##GPIO.setup(21, GPIO.OUT) #green
##GPIO.setup(26, GPIO.IN) #button

def GPIO_Wait_Switch(pin,wait_time = 1, SWITCH_MODE= GPIO.HIGH, Indicator_Pin = False): # Will wait for pin to switch to the SWITCH_MODE setting. If not will sleep for wait_time seconds.
def GPIO_Wait_Switch(pin,wait_time = 1, SWITCH_MODE= 1, Indicator_Pin = False): # Will wait for pin to switch to the SWITCH_MODE setting. If not will sleep for wait_time seconds.
if "GPIO" not in sys.modules: # If does not have GPIO will automatically pass through.
GPIO.setmode(GPIO.BOARD)
GPIO.setup(pin,GPIO.IN)
Expand Down
45 changes: 34 additions & 11 deletions AATC_Monitor_Viewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,14 +191,14 @@ def MakeFlightSprites(Message,RawFlightList):
for Flight in RawFlightList:
#Start Sprite
Coords = ast.literal_eval(Flight[StartCoordsIndex])
Coord = AATC_Coordinate.Coordinate(Coords[0],Coords[1],Coords[2],0.0001,0.0001,0.00001)
Coord = AATC_Coordinate.Coordinate(Coords[0],Coords[1],Coords[2],0.001,0.001,0.0001)
Text = "F:"+ str(Flight[FlightIDIndex])+" D:"+ str(Flight[DroneIDIndex])+ "ST:"+str(Flight[StartTimeIndex])
Colour = (0,0,255)
FlightList.append(Monitor_Sprite(Coord,"StartPoint",Text,Colour))

#End Sprite
Coords = ast.literal_eval(Flight[EndCoordsIndex])
Coord = AATC_Coordinate.Coordinate(Coords[0],Coords[1],Coords[2],0.0001,0.0001,0.00001)
Coord = AATC_Coordinate.Coordinate(Coords[0],Coords[1],Coords[2],0.001,0.001,0.0001)
Text = "F:"+ str(Flight[FlightIDIndex])+" D:"+ str(Flight[DroneIDIndex])+ "ETA:"+str(Flight[ETAIndex])
Colour = (255,0,0)
FlightList.append(Monitor_Sprite(Coord,"EndPoint",Text,Colour))
Expand Down Expand Up @@ -270,14 +270,33 @@ def MakeSprites(M):
print("Refreshed data")
return SpriteList #All sprites which were sucessfully created

class TimeWarper:
"""
This class provides a convinent way to calculate the time warp factor of a variable frame rate game.
The time warp will be relative to the target frame rate. If the warp is greater that of the minimum frame rate then the minimum time warp is taken.
"""
def __init__(self,targetFrameRate = 60,minimumFrameRate = 1):
self.targetFrameRate = targetFrameRate
self.minimumFrameRate = minimumFrameRate
self.Time = time.time()

def GetTimeWarp(self):
TimeWarpFactor = (time.time()-self.Time)*self.targetFrameRate
self.Time = time.time()
return min([self.targetFrameRate/self.minimumFrameRate,TimeWarpFactor])

xpixel = 1200
ypixel = 700



xpixel = 800
ypixel = 550
Refresh_Delay = 60
clock = pygame.time.Clock()
pressed = pygame.key.get_pressed
Exit = "N"



while Exit != "Y":
try:
M = AATC_Monitor.CreateMonitorInterface(IP = "127.0.0.1",Port = 8001)
Expand All @@ -293,10 +312,14 @@ def MakeSprites(M):
for sprite in Sprites:
MonCamera.AddDrawObject(sprite,False)


TimeWarp = TimeWarper()
Last_Refresh_Time = time.time()
refresh = False
while not refresh:
MonCamera.CameraWipe()
TimeWarpFactor = TimeWarp.GetTimeWarp()

if time.time() >= (Last_Refresh_Time + Refresh_Delay):
refresh = True
for event in pygame.event.get():
Expand All @@ -320,18 +343,18 @@ def MakeSprites(M):

CameraCoord = MonCamera.Get_Coord()
if pressed()[pygame.K_w]: #Shift camera
MonCamera.IncrementCameraCoordY(-0.01*CameraCoord.Get_XSize()) #/ as Greater zoom means need more fidelety
MonCamera.IncrementCameraCoordY(-0.01*CameraCoord.Get_XSize()*TimeWarpFactor) #/ as Greater zoom means need more fidelety
if pressed()[pygame.K_s]:
MonCamera.IncrementCameraCoordY(0.01*CameraCoord.Get_XSize())
MonCamera.IncrementCameraCoordY(0.01*CameraCoord.Get_XSize()*TimeWarpFactor)
if pressed()[pygame.K_a]:
MonCamera.IncrementCameraCoordX(-0.01*CameraCoord.Get_XSize())
MonCamera.IncrementCameraCoordX(-0.01*CameraCoord.Get_XSize()*TimeWarpFactor)
if pressed()[pygame.K_d]:
MonCamera.IncrementCameraCoordX(0.01*CameraCoord.Get_XSize())
MonCamera.IncrementCameraCoordX(0.01*CameraCoord.Get_XSize()*TimeWarpFactor)

if pressed()[pygame.K_q]:#Zoom out
MonCamera.SetZoom(0.99*MonCamera.GetZoom())
MonCamera.SetZoom(MonCamera.GetZoom()*0.99**TimeWarpFactor)
if pressed()[pygame.K_e]:#Zoom in
MonCamera.SetZoom(1.01*MonCamera.GetZoom())
MonCamera.SetZoom(MonCamera.GetZoom()*1.01**TimeWarpFactor)

if pressed()[pygame.K_SPACE]:#Zoom in
refresh = True
Expand All @@ -340,7 +363,7 @@ def MakeSprites(M):
MonCamera.UpdateCameraSize()
MonCamera.Draw()
pygame.display.flip()
clock.tick(60)
clock.tick(20)



Expand Down
4 changes: 2 additions & 2 deletions AATC_NoFlyZoneGrapher.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ def GetNoFlyZones(self):

return ProcessedData

def Make_Values(self,NoFlyZoneData):
graph = AATC_AStar.DynoGraph(ABSlot = 1)
def Make_Values(self,NoFlyZoneData,ABSlot = 1):
graph = AATC_AStar.DynoGraph(ABSlot = ABSlot)
graph.ImportGraph()
Values = {}
for Zone in NoFlyZoneData:
Expand Down
50 changes: 42 additions & 8 deletions AATC_Server_002.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import codecs,ast,socket,recvall,os,math,random,time,pickle
import AATC_AStar,AATC_DB, AATC_Crypto,AATC_Config
import AATC_AStar,AATC_DB, AATC_Crypto,AATC_Config,AATC_Weather
from AATC_Coordinate import *

def GetTime():
Expand Down Expand Up @@ -134,8 +134,8 @@ def ProcessCommand(self,Command,Arguments):
Sucess,Message,Data = self.GetUserID(Arguments)
elif Command == "GetUsername":
Sucess,Message,Data = self.GetUsername(Arguments)
elif Command == "SetUserPublicVisibleFlights":
Sucess,Message,Data = self.SetUserPublicVisibleFlights(Arguments)
elif Command == "SetFlightVisibility":
Sucess,Message,Data = self.SetFlightVisibility(Arguments)
elif Command == "SetAccountType":
Sucess,Message,Data = self.SetAccountType(Arguments)
elif Command == "UserChangePassword":
Expand Down Expand Up @@ -274,9 +274,9 @@ def AddUser(self,Arguments):
return Sucess,Message,[]


def SetUserPublicVisibleFlights(self,Arguments):
def SetFlightVisibility(self,Arguments):
Value = Arguments[0]
Sucess,Message = self.DB.SetUserPublicVisibleFlights(self.ClientID,Value)
Sucess,Message = self.DB.SetFlightVisibility(self.ClientID,Value)
return Sucess,Message,[]


Expand Down Expand Up @@ -365,13 +365,19 @@ def AddFlight(self,Arguments):
DroneData = DroneData[0]
SpeedIndex,RangeIndex = Columns.index("DroneSpeed"),Columns.index("DroneRange")
DroneSpeed,DroneRange = DroneData[SpeedIndex],DroneData[RangeIndex]


Weather_Estimator = AATC_Weather.OWM_Control()
Estimated_Drone_Speed = Weather_Estimator.Get_Ajusted_Speed(CoordList[0]["Coords"],CoordList[-1]["Coords"],DroneSpeed,Time)
TotalDistance = 0
for x in range(len(CoordList)):
if x != 0: #If not first Coord add the difference in distance to time etc
Distance = DeltaCoordToMetres(CoordList[x]["Coords"],CoordList[x-1]["Coords"]) #Gets distance in metres
TotalDistance += Distance
DeltaTime = Distance/DroneSpeed

if AATC_Config.ENABLE_FINE_SPEED_ESTIMATION:
Estimated_Drone_Speed = Weather_Estimator.Get_Ajusted_Speed(CoordList[x]["Coords"],CoordList[x-1]["Coords"],DroneSpeed,Time)
time.sleep(AATC_Config.OWM_SLEEP_TIME)
DeltaTime = Distance/Estimated_Drone_Speed
Time = Time + DeltaTime
CoordList[x]["Time"] = Time

Expand All @@ -388,9 +394,13 @@ def AddFlight(self,Arguments):
FlightID = self.DB.cur.fetchall()[0][0]
######################
######################

Waypoints = []

for WaypointNumber in range(len(CoordList)):
self.DB.AddWaypoint(self.ClientID,FlightID,WaypointNumber+1,CoordList[WaypointNumber]["Coords"],CoordList[WaypointNumber]["Time"])
Waypoints.append((FlightID,WaypointNumber+1,str(CoordList[WaypointNumber]["Coords"]),int(CoordList[WaypointNumber]["Time"]),0))

self.DB.AddWaypoints(self.ClientID,FlightID,Waypoints)

return True,"['FlightID','NumberOfWaypoints','StartTime','EndTime','Distance']",[(FlightID,len(CoordList),StartTime,EndTime,TotalDistance)] #Returns data about the flight

Expand Down Expand Up @@ -509,7 +519,31 @@ def Login(self,Arguments):



class WebConnection(UserConnection):
def __init__(self,UserID):
self.ClientID = UserID
self.DB = AATC_DB.DBConnection()
self.Thread_Name = "[WEB FOR UID "+str(self.ClientID)+"]"



def Main(self,packet):
Command, Arguments = packet[0],packet[1]
try:
Sucess,Message,Data = self.ProcessCommand(Command,Arguments)

except Exception as e:
Sucess,Message,Data = False,"An Error occured"+str(e),[]
print("Error occured with UserID:",str(self.ClientID),". Error :",str(e),". Sending failure message")


self.DB.Exit()
return Sucess,Message,Data

def Login(self,Arguments):
Username,Password = Arguments[0],Arguments[1]
Sucess,Message,UserID = self.DB.CheckCredentials(Username,Password)
return Sucess,Message,UserID



Expand Down
25 changes: 25 additions & 0 deletions AATC_Weather.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import pyowm, AATC_Coordinate, math,time

def Get_OWM():
owm = pyowm.OWM('5b943c4857a45d75ef7ee9b301666fa8')

class OWM_Control:
def __init__(self):
self.owm = pyowm.OWM('5b943c4857a45d75ef7ee9b301666fa8')

def Get_Ajusted_Speed(self,CoordA,CoordB,Speed,At_Time = time.time()):
try:

forecast = self.owm.daily_forecast_at_coords(CoordA.Get_Y(),CoordA.Get_X())
wind = forecast.get_weather_at(int(At_Time)).get_wind()

bearing = AATC_Coordinate.GetBearing(CoordA,CoordB)
wind_bearing = AATC_Coordinate.Reverse_Angle(wind["deg"])

Vx = Speed*math.sin(AATC_Coordinate.toRadian(bearing))+ wind["speed"]*math.sin(AATC_Coordinate.toRadian(wind_bearing))
Vy = Speed*math.cos(AATC_Coordinate.toRadian(bearing))+ wind["speed"]*math.cos(AATC_Coordinate.toRadian(wind_bearing))
V = math.sqrt(Vx**2+Vy**2)
return V
except:
return Speed

23 changes: 6 additions & 17 deletions HedaBot.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import telepot,time,random,multiprocessing,AATC_DB,AATC_GPIO
import telepot,time,random,multiprocessing,AATC_DB,AATC_GPIO,SkyrimQuote #Skyrim quote just gets a random quote from skyrim
import AATC_Server_002 as AATC_Server


Expand Down Expand Up @@ -202,7 +202,7 @@ def processInput(self,messageText,chat_id):
self.DB.Bot_flushStack(chat_id)
return "Command cancelled"
elif "/quote" == messageText:
return self.GetQuote()
return SkyrimQuote.SkyrimQuote()
else:
self.DB.Bot_flushStack(chat_id)
messageText = messageText.replace("/","")
Expand Down Expand Up @@ -234,18 +234,6 @@ def processInput(self,messageText,chat_id):
except Exception as e:
return "Error processing message "+str(e) + "\n" + self.ShowCommandsList

def GetQuote(self):
with open("SkyrimDialogue.txt","r") as f:
for i,line in enumerate(f):
pass

lineNum = random.randint(0,i+1)
with open("SkyrimDialogue.txt","r") as f:
for x in range(lineNum):
line = f.readline()
response = line.rstrip().split("\t")[-1:][0]
return response




Expand Down Expand Up @@ -307,8 +295,8 @@ def convertDBStack(result,CommandDictionary):
packet = (command,arguments)
return packet

def SplitWaypoints(string):
waypoints = string.split("\n")
def SplitWaypoints(string,MARKER = "\n"):
waypoints = string.split(MARKER)
return waypoints

def ShowCommands():
Expand All @@ -329,6 +317,7 @@ def CreateCommandDictionary():
#####################################################

Commands["GetNoFlyZones"] = {}
Commands["RemoveNoFlyZone"] = {1: {'Type': int, 'Query': 'Enter ZoneID'}}
Commands["AddNoFlyZone"] = {1: {'Type': str, 'Query': 'Enter first coordinate'},
2: {'Type': str, 'Query': 'Enter second coordinate'},
3: {'Type': int, 'Query': 'Enter level of NoFlyZone'}}
Expand Down Expand Up @@ -490,7 +479,7 @@ def CreateCommandDictionary():



BOT_TOKEN = "YOUR TOKEN HERE"
BOT_TOKEN = "472230564:AAEHTSJ446LE_BO_hQ8B4PeVmUTrB8gRsEA"
if __name__ == "__main__":
bot = telepot.Bot(BOT_TOKEN)
heda = Telebot()
Expand Down

1 comment on commit 20164b3

@Scratchcat1
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-Added TimeWarp feature to AATC_Monitor. Movement now independant of framerate.

Please sign in to comment.