korg.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 #
3 # joystick input driver for Korg NanoKontrol input device
4 #
5 # Author: Austin Hendrix
6 # Author: Allison Thackston
7 
8 import rospy
9 import rospkg
10 import rosparam
11 
12 import pygame
13 import pygame.midi
14 
15 from sensor_msgs.msg import Joy
16 
17 
18 class KorgNanoKontrol(object):
19 
20  ''' Class to connect to and publish the Korg NanoKontrol midi device
21  as a ros joystick
22  '''
23 
24  def __init__(self):
25  ''' connect to midi device and set up ros
26  '''
27  pygame.midi.init()
28  devices = pygame.midi.get_count()
29  if devices < 1:
30  rospy.logerr("No MIDI devices detected")
31  exit(-1)
32  rospy.loginfo("Found %d MIDI devices" % devices)
33 
34  input_dev = int(rospy.get_param("~input_dev",
35  pygame.midi.get_default_input_id))
36 
37  rospy.loginfo("Using input device %d" % input_dev)
38 
39  self.controller = pygame.midi.Input(input_dev)
40 
41  # load in default parameters if not set
42  if not rospy.has_param('~modes'):
43  rospack = rospkg.RosPack()
44  paramlist = rosparam.load_file(rospack.get_path('korg_nanokontrol') +
45  '/config/nanokontrol_config.yaml')
46  for params, ns in paramlist:
47  rosparam.upload_params(ns, params)
48 
49  self.modes = rospy.get_param('~modes')
50 
51  # determine how axis should be interpreted
52  self.center_axis = rospy.get_param('~center_axis', True)
53 
54  self.msg = Joy()
55  self.mode = None
56 
57  self.pub = rospy.Publisher('joy', Joy, queue_size=10, latch=True)
58 
59  def finish(self):
60  del self.controller
61  pygame.midi.quit()
62 
63  def update(self):
64  ''' run the update hook (poll the midi controller, publish the message)
65  '''
66  while self.controller.poll():
67  data = self.controller.read(1)
68  if self.mode == None:
69  self.set_mode(self.guess_mode(data))
70  else:
71  self.pub_data(data)
72 
73  def set_mode(self, mode):
74  ''' Set up the message for the correct mode
75  '''
76  if not mode == None:
77  self.mode = mode
78  self.msg.axes = [0]*len(self.modes[mode]['control_axis'])
79  self.msg.buttons = [0]*len(self.modes[mode]['control_buttons'])
80  self.msg.buttons.append(mode)
81 
82  def guess_mode(self, data):
83  ''' Given data, try to guess the mode we are in
84  '''
85  for event in data:
86  control = event[0]
87 
88  # look for continuous controller commands
89  if (control[0] & 0xF0) == 176:
90  control_id = control[1] | ((control[0] & 0x0F) << 8)
91 
92  # guess initial mode based on command
93  candidate = None
94  for index, control_mode in enumerate(self.modes):
95  if control_id in control_mode['control_axis']:
96  if candidate is not None:
97  candidate = None
98  break
99  candidate = index
100 
101  if control_id in control_mode['control_buttons']:
102  if candidate is not None:
103  candidate = None
104  break
105  candidate = index
106  if not candidate:
107  rospy.loginfo("determining mode..")
108  return candidate
109 
110  def clip(self, min, max, val):
111  if val < min:
112  val = min
113  if val > max:
114  val = max
115  return val
116 
117  def pub_data(self, data):
118  ''' Given data, interpret into Joy message and publish
119  '''
120  do_publish = False
121  self.msg.header.stamp = rospy.Time.now()
122  for event in data:
123  control = event[0]
124  # @todo use timestamp from msg
125  # timestamp = event[1]
126 
127  # look for continuous controller commands
128  if (control[0] & 0xF0) == 176:
129  control_id = control[1] | ((control[0] & 0x0F) << 8)
130 
131  control_axis = self.modes[self.mode]['control_axis']
132  control_buttons = self.modes[self.mode]['control_buttons']
133 
134  if control_id in control_axis:
135  if self.center_axis:
136  control_val = self.clip(-1.0, 1.0,
137  float(control[2] - 63) / 63.0)
138  else:
139  control_val = self.clip(0.0, 1.0,
140  float(control[2]) / 127)
141 
142  axis = control_axis.index(control_id)
143  self.msg.axes[axis] = control_val
144  do_publish = True
145 
146  if control_id in control_buttons:
147  button = control_buttons.index(control_id)
148  if control[2] != 0:
149  self.msg.buttons[button] = 1
150  else:
151  self.msg.buttons[button] = 0
152  do_publish = True
153 
154  # look for mode commands
155  elif control[0] == 79:
156  self.set_mode(control[1])
157  do_publish = True
158 
159  if do_publish:
160  self.pub.publish(self.msg)
def clip(self, min, max, val)
Definition: korg.py:110


korg_nanokontrol
Author(s): Austin Hendrix, Allison Thackston
autogenerated on Mon Jun 10 2019 13:45:15