Skip to content

Commit 902c00a

Browse files
authored
Merge pull from ZenithVal/Leonic-multiLeash
Leonic Rewrite
2 parents d254ab9 + 39b441c commit 902c00a

9 files changed

Lines changed: 746 additions & 273 deletions

File tree

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
Controllers/__pycache__/DataController.cpython-310.pyc
3+
Controllers/__pycache__/PackageController.cpython-310.pyc
4+
Controllers/__pycache__/ThreadController.cpython-310.pyc

Config.json

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,24 @@
55
"RunDeadzone": 0.70,
66
"WalkDeadzone": 0.15,
77
"StrengthMultiplier": 1.2,
8-
"ActiveDelay": 0.1,
8+
"TurningEnabled": false,
9+
"TurningMultiplier": 0.75,
10+
"TurningDeadzone": 0.15,
11+
"TurningGoal": 90,
12+
"ActiveDelay": 0.1,
913
"InactiveDelay": 0.5,
10-
"Logging": true,
11-
"XboxJoystickMovement": false,
12-
"Parameters":
14+
"Logging": false,
15+
"XboxJoystickMovement": false,
16+
17+
"PhysboneParameters":
18+
[
19+
"Leash"
20+
],
21+
"DirectionalParameters":
1322
{
14-
"I GAVE UP ON THESE, THEY DON'T WORK": "if someone knows how, lmk lol",
15-
"Z_Positive_Param": "/avatar/parameters/Leash_Z+",
16-
"Z_Negative_Param": "/avatar/parameters/Leash_Z-",
17-
"X_Positive_Param": "/avatar/parameters/Leash_X+",
18-
"X_Negative_Param": "/avatar/parameters/Leash_Z-",
19-
"LeashGrab_Param": "/avatar/parameters/Leash_IsGrabbed",
20-
"LeashStretch_Param": "/avatar/parameters/Leash_Stretch"
23+
"Z_Positive_Param": "Leash_Z+",
24+
"Z_Negative_Param": "Leash_Z-",
25+
"X_Positive_Param": "Leash_X+",
26+
"X_Negative_Param": "Leash_X-"
2127
}
22-
}
28+
}

Controllers/DataController.py

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
import sys
2+
import time
3+
import ctypes #Required for colored error messages.
4+
5+
DefaultConfig = {
6+
"IP": "127.0.0.1",
7+
"ListeningPort": 9001,
8+
"SendingPort": 9000,
9+
"RunDeadzone": 0.70,
10+
"WalkDeadzone": 0.15,
11+
"StrengthMultiplier": 1.2,
12+
"TurningEnabled": False,
13+
"TurningMultiplier": 0.75,
14+
"TurningDeadzone": .15,
15+
"TurningGoal": 90,
16+
"ActiveDelay": 0.1,
17+
"InactiveDelay": 0.5,
18+
"Logging": True,
19+
"XboxJoystickMovement": False,
20+
21+
"PhysboneParameters":
22+
[
23+
"Leash"
24+
],
25+
26+
"DirectionalParameters":
27+
{
28+
"Z_Positive_Param": "Leash_Z+",
29+
"Z_Negative_Param": "Leash_Z-",
30+
"X_Positive_Param": "Leash_X+",
31+
"X_Negative_Param": "Leash_X-"
32+
}
33+
}
34+
35+
36+
class ConfigSettings:
37+
38+
def __init__(self, configData):
39+
self.setSettings(configData) #Set config values
40+
41+
def setSettings(self, configJson):
42+
try:
43+
self.IP = configJson["IP"]
44+
self.ListeningPort = configJson["ListeningPort"]
45+
self.SendingPort = configJson["SendingPort"]
46+
self.RunDeadzone = configJson["RunDeadzone"]
47+
self.WalkDeadzone = configJson["WalkDeadzone"]
48+
self.StrengthMultiplier = configJson["StrengthMultiplier"]
49+
self.TurningEnabled = configJson["TurningEnabled"]
50+
self.TurningMultiplier = configJson["TurningMultiplier"]
51+
self.TurningDeadzone = configJson["TurningDeadzone"]
52+
self.TurningGoal = (configJson["TurningGoal"]/180)
53+
self.ActiveDelay = configJson["ActiveDelay"]
54+
self.InactiveDelay = configJson["InactiveDelay"]
55+
self.Logging = configJson["Logging"]
56+
self.XboxJoystickMovement = configJson["XboxJoystickMovement"]
57+
except Exception as e:
58+
print('\x1b[1;31;40m' + 'Malformed config file. Loading default values.' + '\x1b[0m')
59+
print(e,"was the exception\n")
60+
self.IP = DefaultConfig["IP"]
61+
self.ListeningPort = DefaultConfig["ListeningPort"]
62+
self.SendingPort = DefaultConfig["SendingPort"]
63+
self.RunDeadzone = DefaultConfig["RunDeadzone"]
64+
self.WalkDeadzone = DefaultConfig["WalkDeadzone"]
65+
self.StrengthMultiplier = DefaultConfig["StrengthMultiplier"]
66+
self.TurningEnabled = DefaultConfig["TurningEnabled"]
67+
self.TurningMultiplier = DefaultConfig["TurningMultiplier"]
68+
self.TurningDeadzone = DefaultConfig["TurningDeadzone"]
69+
self.TurningGoal = (DefaultConfig["TurningGoal"]/180)
70+
self.ActiveDelay = DefaultConfig["ActiveDelay"]
71+
self.InactiveDelay = DefaultConfig["InactiveDelay"]
72+
self.Logging = DefaultConfig["Logging"]
73+
self.XboxJoystickMovement = DefaultConfig["XboxJoystickMovement"]
74+
time.sleep(3)
75+
76+
def addGamepadControls(self, gamepad, runButton):
77+
self.gamepad = gamepad
78+
self.runButton = runButton
79+
80+
def printInfo(self):
81+
print('\x1b[1;32;40m' + 'OSCLeash is Running!' + '\x1b[0m')
82+
83+
if self.IP == "127.0.0.1":
84+
print("IP: Localhost")
85+
else:
86+
print("IP: Not Localhost? Wack.")
87+
88+
print(f"Listening on port {self.ListeningPort}\n Sending on port {self.SendingPort}")
89+
print("Run Deadzone of {:.0f}".format(self.RunDeadzone*100)+"% stretch")
90+
print("Walking Deadzone of {:.0f}".format(self.WalkDeadzone*100)+"% stretch")
91+
print("Delays of {:.0f}".format(self.ActiveDelay*1000),"& {:.0f}".format(self.InactiveDelay*1000),"ms")
92+
if self.TurningEnabled:
93+
print(f"Turning is enabled:\n\tMultiplier of {self.TurningMultiplier}\n\tDeadzone of {self.TurningDeadzone}\n\tGoal of {self.TurningGoal*180}°")
94+
95+
class Leash:
96+
97+
def __init__(self, paraName, contacts, settings: ConfigSettings):
98+
99+
self.Name: str = paraName
100+
self.settings = settings
101+
102+
self.Stretch: float = 0
103+
self.Z_Positive: float = 0
104+
self.Z_Negative: float = 0
105+
self.X_Positive: float = 0
106+
self.X_Negative: float = 0
107+
108+
# Booleans for thread logic
109+
self.Grabbed: bool = False
110+
self.wasGrabbed: bool = False
111+
self.Active: bool = False
112+
113+
if settings.TurningEnabled:
114+
self.LeashDirection = paraName.split("_")[-1]
115+
116+
self.Z_Positive_ParamName: str = contacts["Z_Positive_Param"]
117+
self.Z_Negative_ParamName: str = contacts["Z_Negative_Param"]
118+
self.X_Positive_ParamName: str = contacts["X_Positive_Param"]
119+
self.X_Negative_ParamName: str = contacts["X_Negative_Param"]
120+
121+
def resetMovement(self):
122+
self.Z_Positive: float = 0
123+
self.Z_Negative: float = 0
124+
self.X_Positive: float = 0
125+
self.X_Negative: float = 0
126+
127+
def printDirections(self):
128+
print("\nContact Directions:\n")
129+
130+
print("{}: {}".format(self.Z_Positive_ParamName, self.Z_Positive))
131+
print("{}: {}".format(self.Z_Negative_ParamName, self.Z_Negative))
132+
print("{}: {}".format(self.X_Positive_ParamName, self.X_Positive))
133+
print("{}: {}".format(self.X_Negative_ParamName, self.X_Negative))

Controllers/PackageController.py

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
from array import array
2+
import time
3+
import sys
4+
import ctypes #Required for colored error messages.
5+
from pythonosc.dispatcher import Dispatcher
6+
from pythonosc import osc_server
7+
from threading import Lock, Thread
8+
9+
from Controllers.DataController import Leash
10+
from Controllers.ThreadController import Program
11+
12+
class Package:
13+
14+
def __init__(self, leashCollection):
15+
self.__dispatcher = Dispatcher()
16+
self.__statelock = Lock()
17+
try:
18+
if len(leashCollection) == 0: raise Exception("Leash collection empty within Package manager.")
19+
self.leashes = leashCollection
20+
except Exception as e:
21+
print(e)
22+
time.sleep(5)
23+
24+
def listen(self):
25+
# parameters to read per leash
26+
self.listenLeash(self.leashes)
27+
self.listenParam(self.leashes[0])
28+
29+
def listenLeash(self, leashCollection):
30+
for leash in leashCollection:
31+
self.__dispatcher.map(f'/avatar/parameters/{leash.Name}_Stretch',self.__updateStretch, leash) #Physbone Stretch Value
32+
self.__dispatcher.map(f'/avatar/parameters/{leash.Name}_IsGrabbed',self.__updateGrabbed, leash) #Physbone Grab Status
33+
34+
def listenParam(self, leash):
35+
self.__dispatcher.map(f'/avatar/parameters/{leash.Z_Positive_ParamName}',self.__updateZ_Positive) #Z Positive
36+
self.__dispatcher.map(f'/avatar/parameters/{leash.Z_Negative_ParamName}',self.__updateZ_Negative) #Z Negative
37+
self.__dispatcher.map(f'/avatar/parameters/{leash.X_Positive_ParamName}',self.__updateX_Positive) #X Positive
38+
self.__dispatcher.map(f'/avatar/parameters/{leash.X_Negative_ParamName}',self.__updateX_Negative) #X Negative
39+
40+
def __updateZ_Positive(self, addr, value):
41+
try:
42+
for leash in self.leashes:
43+
self.__statelock.acquire()
44+
leash.Z_Positive = value
45+
self.__statelock.release()
46+
except Exception as e:
47+
print(e)
48+
time.sleep(5)
49+
50+
def __updateZ_Negative(self, addr, value):
51+
try:
52+
for leash in self.leashes:
53+
self.__statelock.acquire()
54+
leash.Z_Negative = value
55+
self.__statelock.release()
56+
except Exception as e:
57+
print(e)
58+
time.sleep(5)
59+
60+
def __updateX_Positive(self, addr, value):
61+
try:
62+
for leash in self.leashes:
63+
self.__statelock.acquire()
64+
leash.X_Positive = value
65+
self.__statelock.release()
66+
except Exception as e:
67+
print(e)
68+
time.sleep(5)
69+
70+
def __updateX_Negative(self, addr, value):
71+
try:
72+
for leash in self.leashes:
73+
self.__statelock.acquire()
74+
leash.X_Negative = value
75+
self.__statelock.release()
76+
except Exception as e:
77+
print(e)
78+
time.sleep(5)
79+
80+
81+
def __updateStretch(self, addr, extraArgs, value):
82+
try:
83+
leash: Leash = extraArgs[0]
84+
self.__statelock.acquire()
85+
leash.Stretch = value
86+
self.__statelock.release()
87+
except Exception as e:
88+
print(e)
89+
time.sleep(5)
90+
91+
def __updateGrabbed(self, addr, extraArgs, value):
92+
try:
93+
currLeash: Leash = extraArgs[0]
94+
self.__statelock.acquire()
95+
currLeash.Grabbed = value
96+
97+
threadInProgress = False
98+
if currLeash.Grabbed:
99+
for leash in self.leashes:
100+
if not leash.Name == currLeash.Name and leash.Active:
101+
threadInProgress = True
102+
103+
if not threadInProgress:
104+
program = Program()
105+
currLeash.Active = True
106+
Thread(target=program.leashRun, args=(currLeash,)).start()
107+
108+
self.__statelock.release()
109+
except Exception as e:
110+
print(e)
111+
time.sleep(5)
112+
113+
def runServer(self, IP, Port):
114+
try:
115+
osc_server.ThreadingOSCUDPServer((IP, Port), self.__dispatcher).serve_forever()
116+
except Exception as e:
117+
print('\x1b[1;31;41m' + ' ' + '\x1b[0m')
118+
print('\x1b[1;31;40m' + ' Warning: An application might already be running on this port! ' + '\x1b[0m')
119+
print('\x1b[1;31;41m' + ' \n' + '\x1b[0m')
120+
print(e)
121+
# No delay here as error message is displayed somewhere else when this fails

0 commit comments

Comments
 (0)