mirror of
https://github.com/Astatin3/autoPlanner.git
synced 2026-06-08 23:58:00 -06:00
Add exporting
This commit is contained in:
@@ -23,4 +23,8 @@ python3 ./main.py
|
||||
- In button mode select buttons on the driver and operator controllers.
|
||||
|
||||
##### "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 = [
|
||||
pathEditor.pathEditor(render),
|
||||
buttonEditor.buttonEditor(render, pathEditor),
|
||||
export.export(pg, render)
|
||||
export.export(pg, render, buttonEditor)
|
||||
]
|
||||
|
||||
tabs[tabIndex].load()
|
||||
@@ -51,6 +51,7 @@ def addTab(i):
|
||||
|
||||
def onClick(pos):
|
||||
global tabIndex
|
||||
tabs[tabIndex].unload()
|
||||
tabIndex = i
|
||||
tabs[tabIndex].load()
|
||||
render.renderElements(pos)
|
||||
@@ -100,6 +101,7 @@ while running:
|
||||
elif event.type == pg.KEYDOWN:
|
||||
tabs[tabIndex].keyDown(event.key)
|
||||
if event.key == pg.K_TAB:
|
||||
tabs[tabIndex].unload()
|
||||
tabIndex = (tabIndex + 1) % len(tabs)
|
||||
tabs[tabIndex].load()
|
||||
render.renderElements(pg.mouse.get_pos())
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
numpy
|
||||
pygame
|
||||
crossfiledialog
|
||||
+9
-1
@@ -17,6 +17,7 @@ keyFrames = []
|
||||
matchLength = 15
|
||||
TPS = 50
|
||||
|
||||
tickTime = round(1/TPS*1000)
|
||||
matchTicks = matchLength * TPS
|
||||
displayTickResolution = 4
|
||||
displayTicks = round(matchTicks / displayTickResolution)
|
||||
@@ -165,6 +166,9 @@ def getButtonFrameAtPos(index):
|
||||
def getRobotAtIndex(index):
|
||||
prevFrame, nextFrame = getSurroundingPosFrames(index)
|
||||
|
||||
# print(prevFrame)
|
||||
# print(nextFrame)
|
||||
|
||||
if prevFrame == None and nextFrame == None:
|
||||
return (0,0), 0
|
||||
if prevFrame == None:
|
||||
@@ -643,4 +647,8 @@ class buttonEditor:
|
||||
else:
|
||||
self.updateNodes(True)
|
||||
|
||||
self.refresh()
|
||||
self.refresh()
|
||||
|
||||
|
||||
def unload(self):
|
||||
pass
|
||||
+224
-4
@@ -1,16 +1,224 @@
|
||||
import crossfiledialog
|
||||
import struct
|
||||
import copy
|
||||
|
||||
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:
|
||||
name = "Export"
|
||||
|
||||
def __init__(self, tmppg, tmprender):
|
||||
def __init__(self, tmppg, tmprender, tmpbuttonEditor):
|
||||
global pg
|
||||
pg = tmppg
|
||||
global render
|
||||
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):
|
||||
pass
|
||||
@@ -28,5 +236,17 @@ class export:
|
||||
pass
|
||||
|
||||
def load(self):
|
||||
self.loaded = True
|
||||
|
||||
# for keyFrame in buttonEditor.keyFrames:
|
||||
# keyFrame['timeIndex'] = keyFrame['timeIndex'] * buttonEditor.displayTickResolution
|
||||
|
||||
|
||||
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)
|
||||
+4
-5
@@ -161,12 +161,11 @@ class pathEditor:
|
||||
nodeRotations.pop(clickIndex)
|
||||
refresh()
|
||||
|
||||
|
||||
|
||||
def keyDown(self, key):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
def load(self):
|
||||
refresh()
|
||||
refresh()
|
||||
|
||||
def unload(self):
|
||||
pass
|
||||
+1
-1
@@ -159,7 +159,7 @@ class render():
|
||||
|
||||
def clickElement(self, pos):
|
||||
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)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user