DirectDeviceManager.py 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. """ Class used to create and control vrpn devices """
  2. from direct.showbase.DirectObject import DirectObject
  3. from pandac.PandaModules import *
  4. ANALOG_MIN = -0.95
  5. ANALOG_MAX = 0.95
  6. ANALOG_DEADBAND = 0.125
  7. ANALOG_CENTER = 0.0
  8. try:
  9. myBase = base
  10. except:
  11. myBase = simbase
  12. class DirectDeviceManager(VrpnClient, DirectObject):
  13. def __init__(self, server = None):
  14. # Determine which server to use
  15. if server != None:
  16. # One given as constructor argument
  17. self.server = server
  18. else:
  19. # Check config file, if that fails, use default
  20. self.server = myBase.config.GetString('vrpn-server', 'spacedyne')
  21. # Create a vrpn client
  22. VrpnClient.__init__(self, self.server)
  23. def createButtons(self, device):
  24. return DirectButtons(self, device)
  25. def createAnalogs(self, device):
  26. return DirectAnalogs(self, device)
  27. def createTracker(self, device):
  28. return DirectTracker(self, device)
  29. def createDials(self, device):
  30. return DirectDials(self, device)
  31. def createTimecodeReader(self, device):
  32. return DirectTimecodeReader(self, device)
  33. class DirectButtons(ButtonNode, DirectObject):
  34. buttonCount = 0
  35. def __init__(self, vrpnClient, device):
  36. # Keep track of number of buttons created
  37. DirectButtons.buttonCount += 1
  38. # Create a unique name for this button object
  39. self.name = 'DirectButtons-' + repr(DirectButtons.buttonCount)
  40. # Create a new button node for the given device
  41. ButtonNode.__init__(self, vrpnClient, device)
  42. # Attach node to data graph
  43. self.nodePath = myBase.dataRoot.attachNewNode(self)
  44. def __getitem__(self, index):
  45. if (index < 0) or (index >= self.getNumButtons()):
  46. raise IndexError
  47. return self.getButtonState(index)
  48. def __len__(self):
  49. return self.getNumButtons()
  50. def enable(self):
  51. self.nodePath.reparentTo(myBase.dataRoot)
  52. def disable(self):
  53. self.nodePath.reparentTo(myBase.dataUnused)
  54. def getName(self):
  55. return self.name
  56. def getNodePath(self):
  57. return self.nodePath
  58. def __repr__(self):
  59. str = self.name + ': '
  60. for val in self:
  61. str = str + '%d' % val + ' '
  62. return str
  63. class DirectAnalogs(AnalogNode, DirectObject):
  64. analogCount = 0
  65. def __init__(self, vrpnClient, device):
  66. # Keep track of number of analogs created
  67. DirectAnalogs.analogCount += 1
  68. # Create a unique name for this analog object
  69. self.name = 'DirectAnalogs-' + repr(DirectAnalogs.analogCount)
  70. # Create a new analog node for the given device
  71. AnalogNode.__init__(self, vrpnClient, device)
  72. # Attach node to data graph
  73. self.nodePath = myBase.dataRoot.attachNewNode(self)
  74. # See if any of the general analog parameters are dconfig'd
  75. self.analogDeadband = myBase.config.GetFloat('vrpn-analog-deadband',
  76. ANALOG_DEADBAND)
  77. self.analogMin = myBase.config.GetFloat('vrpn-analog-min',
  78. ANALOG_MIN)
  79. self.analogMax = myBase.config.GetFloat('vrpn-analog-max',
  80. ANALOG_MAX)
  81. self.analogCenter = myBase.config.GetFloat('vrpn-analog-center',
  82. ANALOG_CENTER)
  83. self.analogRange = self.analogMax - self.analogMin
  84. def __getitem__(self, index):
  85. if (index < 0) or (index >= self.getNumControls()):
  86. raise IndexError
  87. return self.getControlState(index)
  88. def __len__(self):
  89. return self.getNumControls()
  90. def enable(self):
  91. self.nodePath.reparentTo(myBase.dataRoot)
  92. def disable(self):
  93. self.nodePath.reparentTo(myBase.dataUnused)
  94. def normalizeWithoutCentering(self, val, minVal = -1, maxVal = 1):
  95. #
  96. # This is the old code that doesn't incorporate the centering fix
  97. #
  98. # First record sign
  99. if val < 0:
  100. sign = -1
  101. else:
  102. sign = 1
  103. # Zero out values in deadband
  104. val = sign * max(abs(val) - self.analogDeadband, 0.0)
  105. # Clamp value between analog range min and max and scale about center
  106. val = min(max(val, self.analogMin), self.analogMax)
  107. # Normalize values to given minVal and maxVal range
  108. return (((maxVal - minVal) *
  109. ((val - self.analogMin) / float(self.analogRange))) + minVal)
  110. def normalize(self, rawValue, minVal = -1, maxVal = 1, sf = 1.0):
  111. aMax = self.analogMax
  112. aMin = self.analogMin
  113. center = self.analogCenter
  114. deadband = self.analogDeadband
  115. range = self.analogRange
  116. # Zero out values in deadband
  117. if (abs(rawValue-center) <= deadband):
  118. return 0.0
  119. # Clamp value between aMin and aMax and scale around center
  120. if (rawValue >= center):
  121. # Convert positive values to range 0 to 1
  122. val = min(rawValue * sf, aMax)
  123. percentVal = ((val - (center + deadband))/
  124. float(aMax - (center + deadband)))
  125. else:
  126. # Convert negative values to range -1 to 0
  127. val = max(rawValue * sf, aMin)
  128. percentVal = -((val - (center - deadband))/
  129. float(aMin - (center - deadband)))
  130. # Normalize values to given minVal and maxVal range
  131. return (((maxVal - minVal) * ((percentVal + 1)/2.0)) + minVal)
  132. def normalizeChannel(self, chan, minVal = -1, maxVal = 1, sf = 1.0):
  133. try:
  134. return self.normalize(self[chan], minVal, maxVal, sfx)
  135. except IndexError:
  136. return 0.0
  137. def getName(self):
  138. return self.name
  139. def getNodePath(self):
  140. return self.nodePath
  141. def __repr__(self):
  142. str = self.name + ': '
  143. for val in self:
  144. str = str + '%.3f' % val + ' '
  145. return str
  146. class DirectTracker(TrackerNode, DirectObject):
  147. trackerCount = 0
  148. def __init__(self, vrpnClient, device):
  149. # Keep track of number of trackers created
  150. DirectTracker.trackerCount += 1
  151. # Create a unique name for this tracker object
  152. self.name = 'DirectTracker-' + repr(DirectTracker.trackerCount)
  153. # Create a new tracker node for the given device
  154. TrackerNode.__init__(self, vrpnClient, device)
  155. # Attach node to data graph
  156. self.nodePath = myBase.dataRoot.attachNewNode(self)
  157. def enable(self):
  158. self.nodePath.reparentTo(myBase.dataRoot)
  159. def disable(self):
  160. self.nodePath.reparentTo(myBase.dataUnused)
  161. def getName(self):
  162. return self.name
  163. def getNodePath(self):
  164. return self.nodePath
  165. def __repr__(self):
  166. return self.name
  167. class DirectDials(DialNode, DirectObject):
  168. dialCount = 0
  169. def __init__(self, vrpnClient, device):
  170. # Keep track of number of dials created
  171. DirectDials.dialCount += 1
  172. # Create a unique name for this dial object
  173. self.name = 'DirectDials-' + repr(DirectDials.dialCount)
  174. # Create a new dial node for the given device
  175. DialNode.__init__(self, vrpnClient, device)
  176. # Attach node to data graph
  177. self.nodePath = myBase.dataRoot.attachNewNode(self)
  178. def __getitem__(self, index):
  179. """
  180. if (index < 0) or (index >= self.getNumDials()):
  181. raise IndexError
  182. """
  183. return self.readDial(index)
  184. def __len__(self):
  185. return self.getNumDials()
  186. def enable(self):
  187. self.nodePath.reparentTo(myBase.dataRoot)
  188. def disable(self):
  189. self.nodePath.reparentTo(myBase.dataUnused)
  190. def getName(self):
  191. return self.name
  192. def getNodePath(self):
  193. return self.nodePath
  194. def __repr__(self):
  195. str = self.name + ': '
  196. for i in range(self.getNumDials()):
  197. str = str + '%.3f' % self[i] + ' '
  198. return str
  199. class DirectTimecodeReader(AnalogNode, DirectObject):
  200. timecodeReaderCount = 0
  201. def __init__(self, vrpnClient, device):
  202. # Keep track of number of timecodeReader created
  203. DirectTimecodeReader.timecodeReaderCount += 1
  204. # Create a unique name for this dial object
  205. self.name = ('DirectTimecodeReader-' +
  206. repr(DirectTimecodeReader.timecodeReaderCount))
  207. # Initialize components of timecode
  208. self.frames = 0
  209. self.seconds = 0
  210. self.minutes = 0
  211. self.hours = 0
  212. # Create a new dial node for the given device
  213. AnalogNode.__init__(self, vrpnClient, device)
  214. # Attach node to data graph
  215. self.nodePath = myBase.dataRoot.attachNewNode(self)
  216. def enable(self):
  217. self.nodePath.reparentTo(myBase.dataRoot)
  218. def disable(self):
  219. self.nodePath.reparentTo(myBase.dataUnused)
  220. def getName(self):
  221. return self.name
  222. def getNodePath(self):
  223. return self.nodePath
  224. def getTime(self):
  225. # Assume only one card, use channel 0
  226. timeBits = int(self.getControlState(0))
  227. self.frames = ((timeBits & 0xF) +
  228. (((timeBits & 0xF0) >> 4) * 10))
  229. self.seconds = (((timeBits & 0x0F00) >> 8) +
  230. (((timeBits & 0xF000) >> 12) * 10))
  231. self.minutes = (((timeBits & 0x0F0000) >> 16) +
  232. (((timeBits & 0xF00000) >> 20) * 10))
  233. self.hours = (((timeBits & 0xF000000) >> 24) +
  234. (((timeBits & 0xF0000000) >> 28) * 10))
  235. self.totalSeconds = ((self.hours * 3600) +
  236. (self.minutes * 60) +
  237. self.seconds +
  238. (self.frames / 30.0))
  239. return (self.hours, self.minutes, self.seconds, self.frames,
  240. self.totalSeconds)
  241. def __repr__(self):
  242. str = ('%s: %d:%d:%d:%d' % ((self.name,) + self.getTime()[:-1]))
  243. return str