mirror of
https://github.com/Astatin3/autoPlanner.git
synced 2026-06-08 23:58:00 -06:00
Add exporting
This commit is contained in:
@@ -24,3 +24,7 @@ python3 ./main.py
|
|||||||
|
|
||||||
##### "Export" Tab:
|
##### "Export" Tab:
|
||||||
- Click export, and save to a file
|
- Click export, and save to a file
|
||||||
|
|
||||||
|
### Known Bugs:
|
||||||
|
- Because the variables don't get transferred over yet, you must click on the button editor tab before exporting.
|
||||||
|
- The driver controller's movement stick is rotated by 90 degrees (Maybe)
|
||||||
@@ -32,7 +32,7 @@ tabIndex = 0
|
|||||||
tabs = [
|
tabs = [
|
||||||
pathEditor.pathEditor(render),
|
pathEditor.pathEditor(render),
|
||||||
buttonEditor.buttonEditor(render, pathEditor),
|
buttonEditor.buttonEditor(render, pathEditor),
|
||||||
export.export(pg, render)
|
export.export(pg, render, buttonEditor)
|
||||||
]
|
]
|
||||||
|
|
||||||
tabs[tabIndex].load()
|
tabs[tabIndex].load()
|
||||||
@@ -51,6 +51,7 @@ def addTab(i):
|
|||||||
|
|
||||||
def onClick(pos):
|
def onClick(pos):
|
||||||
global tabIndex
|
global tabIndex
|
||||||
|
tabs[tabIndex].unload()
|
||||||
tabIndex = i
|
tabIndex = i
|
||||||
tabs[tabIndex].load()
|
tabs[tabIndex].load()
|
||||||
render.renderElements(pos)
|
render.renderElements(pos)
|
||||||
@@ -100,6 +101,7 @@ while running:
|
|||||||
elif event.type == pg.KEYDOWN:
|
elif event.type == pg.KEYDOWN:
|
||||||
tabs[tabIndex].keyDown(event.key)
|
tabs[tabIndex].keyDown(event.key)
|
||||||
if event.key == pg.K_TAB:
|
if event.key == pg.K_TAB:
|
||||||
|
tabs[tabIndex].unload()
|
||||||
tabIndex = (tabIndex + 1) % len(tabs)
|
tabIndex = (tabIndex + 1) % len(tabs)
|
||||||
tabs[tabIndex].load()
|
tabs[tabIndex].load()
|
||||||
render.renderElements(pg.mouse.get_pos())
|
render.renderElements(pg.mouse.get_pos())
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
numpy
|
||||||
|
pygame
|
||||||
|
crossfiledialog
|
||||||
@@ -17,6 +17,7 @@ keyFrames = []
|
|||||||
matchLength = 15
|
matchLength = 15
|
||||||
TPS = 50
|
TPS = 50
|
||||||
|
|
||||||
|
tickTime = round(1/TPS*1000)
|
||||||
matchTicks = matchLength * TPS
|
matchTicks = matchLength * TPS
|
||||||
displayTickResolution = 4
|
displayTickResolution = 4
|
||||||
displayTicks = round(matchTicks / displayTickResolution)
|
displayTicks = round(matchTicks / displayTickResolution)
|
||||||
@@ -165,6 +166,9 @@ def getButtonFrameAtPos(index):
|
|||||||
def getRobotAtIndex(index):
|
def getRobotAtIndex(index):
|
||||||
prevFrame, nextFrame = getSurroundingPosFrames(index)
|
prevFrame, nextFrame = getSurroundingPosFrames(index)
|
||||||
|
|
||||||
|
# print(prevFrame)
|
||||||
|
# print(nextFrame)
|
||||||
|
|
||||||
if prevFrame == None and nextFrame == None:
|
if prevFrame == None and nextFrame == None:
|
||||||
return (0,0), 0
|
return (0,0), 0
|
||||||
if prevFrame == None:
|
if prevFrame == None:
|
||||||
@@ -644,3 +648,7 @@ class buttonEditor:
|
|||||||
self.updateNodes(True)
|
self.updateNodes(True)
|
||||||
|
|
||||||
self.refresh()
|
self.refresh()
|
||||||
|
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
pass
|
||||||
+223
-3
@@ -1,16 +1,224 @@
|
|||||||
|
import crossfiledialog
|
||||||
|
import struct
|
||||||
|
import copy
|
||||||
|
|
||||||
pg = None
|
pg = None
|
||||||
render = None
|
buttonEditor = None
|
||||||
|
events = []
|
||||||
|
|
||||||
|
#Save according to https://github.com/Team4388/2024AcrossTheRidgebotiverse/blob/Prep-For-Denver/src/main/java/frc4388/robot/commands/Autos/neo%20AutoRecoding%20format.txt
|
||||||
|
|
||||||
|
|
||||||
|
moveMultiplier = 0.1
|
||||||
|
rotMultiplier = 1
|
||||||
|
|
||||||
|
|
||||||
|
def buttonsToBytes(buttons):
|
||||||
|
data = 0
|
||||||
|
for i in range(16):
|
||||||
|
data |= buttons[i] << i
|
||||||
|
return data.to_bytes(2, "little", signed=True)
|
||||||
|
|
||||||
|
|
||||||
|
def toByte(num):
|
||||||
|
if num > 255:
|
||||||
|
raise OverflowError
|
||||||
|
return num.to_bytes(1, 'big', signed=False)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def toShort(num):
|
||||||
|
if num > 65535:
|
||||||
|
raise OverflowError
|
||||||
|
return num.to_bytes(2, 'big', signed=True)
|
||||||
|
|
||||||
|
|
||||||
|
def toInt(num):
|
||||||
|
return struct.pack('>i', num)
|
||||||
|
|
||||||
|
|
||||||
|
def toDouble(num):
|
||||||
|
return struct.pack('>d', num)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class xboxController:
|
||||||
|
def __init__(self):
|
||||||
|
self.buttons = [False for i in range(16)]
|
||||||
|
self.leftStick = (0,0)
|
||||||
|
self.rightStick = (0,0)
|
||||||
|
self.LT = -1
|
||||||
|
self.RT = -1
|
||||||
|
self.POV = -1
|
||||||
|
|
||||||
|
|
||||||
|
def getPOVhat(up, down, left, right):
|
||||||
|
if up and right:
|
||||||
|
return 45
|
||||||
|
elif right and down:
|
||||||
|
return 135
|
||||||
|
elif down and left:
|
||||||
|
return 225
|
||||||
|
elif left and up:
|
||||||
|
return 315
|
||||||
|
elif up:
|
||||||
|
return 0
|
||||||
|
elif right:
|
||||||
|
return 90
|
||||||
|
elif down:
|
||||||
|
return 180
|
||||||
|
elif left:
|
||||||
|
return 270
|
||||||
|
else:
|
||||||
|
return -1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def getSticksAtFrame(index):
|
||||||
|
|
||||||
|
fractionIndex = round(index/buttonEditor.displayTickResolution)
|
||||||
|
|
||||||
|
newpos, newrot = buttonEditor.getRobotAtIndex(fractionIndex)
|
||||||
|
oldpos, oldrot = buttonEditor.getRobotAtIndex(fractionIndex-1)
|
||||||
|
|
||||||
|
# print(oldrot-newrot)
|
||||||
|
|
||||||
|
diffPos = ((oldpos[0]-newpos[0])*moveMultiplier, (oldpos[1]-newpos[1])*moveMultiplier)
|
||||||
|
diffRot = (oldrot-newrot)*rotMultiplier
|
||||||
|
|
||||||
|
if abs(diffPos[0]) > 1 or abs(diffPos[1]) > 1 or abs(diffRot) > 1:
|
||||||
|
print("Error! Robot moved too fast!, Try to edit 'Multiplier' values in export.py")
|
||||||
|
return (0, 0), 0
|
||||||
|
|
||||||
|
|
||||||
|
print(diffPos)
|
||||||
|
|
||||||
|
# print(diffRot)
|
||||||
|
|
||||||
|
return diffPos, diffRot
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def getControllersAtFrame(index):
|
||||||
|
controllers = [xboxController(), xboxController()]
|
||||||
|
if index >= buttonEditor.matchTicks:
|
||||||
|
return controllers
|
||||||
|
|
||||||
|
pos, rot = getSticksAtFrame(index)
|
||||||
|
|
||||||
|
controllers[0].leftStick = pos
|
||||||
|
controllers[0].rightStick = (rot,0)
|
||||||
|
|
||||||
|
btns = buttonEditor.getLeftButtonFrame(index)
|
||||||
|
if btns == None:
|
||||||
|
btns = buttonEditor.createBlankController()
|
||||||
|
else:
|
||||||
|
btns = btns['controllers']
|
||||||
|
|
||||||
|
for i in range(len(controllers)):
|
||||||
|
ctrlr = btns[i]
|
||||||
|
|
||||||
|
controllers[i].buttons[0] = ctrlr['A']
|
||||||
|
controllers[i].buttons[1] = ctrlr['B']
|
||||||
|
controllers[i].buttons[2] = ctrlr['X']
|
||||||
|
controllers[i].buttons[3] = ctrlr['Y']
|
||||||
|
|
||||||
|
controllers[i].buttons[4] = ctrlr['LB']
|
||||||
|
controllers[i].buttons[5] = ctrlr['RB']
|
||||||
|
|
||||||
|
controllers[i].buttons[6] = ctrlr['Menu']
|
||||||
|
controllers[i].buttons[7] = ctrlr['Windows']
|
||||||
|
|
||||||
|
controllers[i].buttons[8] = ctrlr['Left_Stick']
|
||||||
|
controllers[i].buttons[9] = ctrlr['Right_Stick']
|
||||||
|
|
||||||
|
controllers[i].LT = (ctrlr['LT']*2)-1
|
||||||
|
controllers[i].RT = (ctrlr['RT']*2)-1
|
||||||
|
|
||||||
|
controllers[i].POV = getPOVhat(ctrlr['Dpad_Up'], ctrlr['Dpad_Down'],
|
||||||
|
ctrlr['Dpad_Left'], ctrlr['Dpad_Right'])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return controllers
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def getFrameData(index):
|
||||||
|
controllers = getControllersAtFrame(index)
|
||||||
|
data = b''
|
||||||
|
for ctrlr in controllers:
|
||||||
|
# print(ctrlr.leftStick[0])
|
||||||
|
data += toDouble(ctrlr.leftStick[0])
|
||||||
|
data += toDouble(ctrlr.leftStick[1])
|
||||||
|
data += toDouble(ctrlr.LT)
|
||||||
|
data += toDouble(ctrlr.RT)
|
||||||
|
data += toDouble(ctrlr.rightStick[0])
|
||||||
|
data += toDouble(ctrlr.rightStick[1])
|
||||||
|
|
||||||
|
data += buttonsToBytes(ctrlr.buttons)
|
||||||
|
|
||||||
|
# for btn in ctrlr.buttons:
|
||||||
|
# data += toBit(data)
|
||||||
|
# print(toBit(data))
|
||||||
|
|
||||||
|
data += toShort(ctrlr.POV)
|
||||||
|
|
||||||
|
data += toInt(index * buttonEditor.tickTime)
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def getHeader():
|
||||||
|
header = toByte(6) # Num Axes per controller
|
||||||
|
header += toByte(1) # Num POVs
|
||||||
|
header += toByte(2) # Num Controllers
|
||||||
|
header += toShort(buttonEditor.matchTicks) # Num Frames
|
||||||
|
return header
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def getData():
|
||||||
|
data = b''
|
||||||
|
for i in range(buttonEditor.matchTicks):
|
||||||
|
data += getFrameData(i)
|
||||||
|
return getHeader() + data
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def save():
|
||||||
|
path = crossfiledialog.save_file('Save auto file', './')
|
||||||
|
# path = "./file.txt"
|
||||||
|
with open(path, "wb") as f:
|
||||||
|
f.write(getData())
|
||||||
|
|
||||||
class export:
|
class export:
|
||||||
name = "Export"
|
name = "Export"
|
||||||
|
|
||||||
def __init__(self, tmppg, tmprender):
|
def __init__(self, tmppg, tmprender, tmpbuttonEditor):
|
||||||
global pg
|
global pg
|
||||||
pg = tmppg
|
pg = tmppg
|
||||||
global render
|
global render
|
||||||
render = tmprender
|
render = tmprender
|
||||||
|
global buttonEditor
|
||||||
|
buttonEditor = tmpbuttonEditor
|
||||||
|
|
||||||
# render.addButton()
|
self.loaded = False
|
||||||
|
|
||||||
|
def getIsSelected():
|
||||||
|
return False
|
||||||
|
|
||||||
|
def getIsVisible():
|
||||||
|
return self.loaded
|
||||||
|
|
||||||
|
def onClick(pos):
|
||||||
|
save()
|
||||||
|
|
||||||
|
render.addButton((round(render.width/4),round(render.screen.get_height()/4),round(render.width/2),round(render.height/2)),
|
||||||
|
"Export", getIsSelected, getIsVisible, onClick)
|
||||||
|
|
||||||
def mouseDown(self, pos):
|
def mouseDown(self, pos):
|
||||||
pass
|
pass
|
||||||
@@ -28,5 +236,17 @@ class export:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def load(self):
|
def load(self):
|
||||||
|
self.loaded = True
|
||||||
|
|
||||||
|
# for keyFrame in buttonEditor.keyFrames:
|
||||||
|
# keyFrame['timeIndex'] = keyFrame['timeIndex'] * buttonEditor.displayTickResolution
|
||||||
|
|
||||||
|
|
||||||
render.clear()
|
render.clear()
|
||||||
pg.display.update()
|
pg.display.update()
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
self.loaded = False
|
||||||
|
|
||||||
|
# for keyFrame in buttonEditor.keyFrames:
|
||||||
|
# keyFrame['timeIndex'] = round(keyFrame['timeIndex'] / buttonEditor.displayTickResolution)
|
||||||
+3
-4
@@ -161,12 +161,11 @@ class pathEditor:
|
|||||||
nodeRotations.pop(clickIndex)
|
nodeRotations.pop(clickIndex)
|
||||||
refresh()
|
refresh()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def keyDown(self, key):
|
def keyDown(self, key):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def load(self):
|
def load(self):
|
||||||
refresh()
|
refresh()
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
pass
|
||||||
+1
-1
@@ -159,7 +159,7 @@ class render():
|
|||||||
|
|
||||||
def clickElement(self, pos):
|
def clickElement(self, pos):
|
||||||
for elem in self.elements:
|
for elem in self.elements:
|
||||||
if elem['type'] == 'button' and self.isInRect(pos, elem['rect']):
|
if elem['type'] == 'button' and elem['getIsVisible']() and self.isInRect(pos, elem['rect']):
|
||||||
elem['onClick'](pos)
|
elem['onClick'](pos)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user