Go to the documentation of this file.00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 import rospy
00009 import rospkg
00010 import rosparam
00011 
00012 import pygame
00013 import pygame.midi
00014 
00015 from sensor_msgs.msg import Joy
00016 
00017 
00018 class KorgNanoKontrol(object):
00019 
00020     ''' Class to connect to and publish the Korg NanoKontrol midi device
00021         as a ros joystick
00022     '''
00023 
00024     def __init__(self):
00025         ''' connect to midi device and set up ros
00026         '''
00027         pygame.midi.init()
00028         devices = pygame.midi.get_count()
00029         if devices < 1:
00030             rospy.logerr("No MIDI devices detected")
00031             exit(-1)
00032         rospy.loginfo("Found %d MIDI devices" % devices)
00033 
00034         input_dev = int(rospy.get_param("~input_dev",
00035                                         pygame.midi.get_default_input_id))
00036 
00037         rospy.loginfo("Using input device %d" % input_dev)
00038 
00039         self.controller = pygame.midi.Input(input_dev)
00040 
00041         
00042         if not rospy.has_param('~modes'):
00043             rospack = rospkg.RosPack()
00044             paramlist = rosparam.load_file(rospack.get_path('korg_nanokontrol') +
00045                                            '/config/nanokontrol_config.yaml')
00046             for params, ns in paramlist:
00047                 rosparam.upload_params(ns, params)
00048 
00049         self.modes = rospy.get_param('~modes')
00050 
00051         
00052         self.center_axis = rospy.get_param('~center_axis', True)
00053 
00054         self.msg = Joy()
00055         self.mode = None
00056 
00057         self.pub = rospy.Publisher('joy', Joy, queue_size=10, latch=True)
00058 
00059     def finish(self):
00060         del self.controller
00061         pygame.midi.quit()
00062 
00063     def update(self):
00064         ''' run the update hook (poll the midi controller, publish the message)
00065         '''
00066         while self.controller.poll():
00067             data = self.controller.read(1)
00068             if self.mode == None:
00069                 self.set_mode(self.guess_mode(data))
00070             else:
00071                 self.pub_data(data)
00072 
00073     def set_mode(self, mode):
00074         ''' Set up the message for the correct mode
00075         '''
00076         if not mode == None:
00077             self.mode = mode
00078             self.msg.axes = [0]*len(self.modes[mode]['control_axis'])
00079             self.msg.buttons = [0]*len(self.modes[mode]['control_buttons'])
00080             self.msg.buttons.append(mode)
00081 
00082     def guess_mode(self, data):
00083         ''' Given data, try to guess the mode we are in
00084         '''
00085         for event in data:
00086             control = event[0]
00087 
00088             
00089             if (control[0] & 0xF0) == 176:
00090                 control_id = control[1] | ((control[0] & 0x0F) << 8)
00091 
00092                 
00093                 candidate = None
00094                 for index, control_mode in enumerate(self.modes):
00095                     if control_id in control_mode['control_axis']:
00096                         if candidate is not None:
00097                             candidate = None
00098                             break
00099                         candidate = index
00100 
00101                     if control_id in control_mode['control_buttons']:
00102                         if candidate is not None:
00103                             candidate = None
00104                             break
00105                         candidate = index
00106                 if not candidate:
00107                     rospy.loginfo("determining mode..")
00108                 return candidate
00109 
00110     def clip(self, min, max, val):
00111         if val < min:
00112             val = min
00113         if val > max:
00114             val = max
00115         return val
00116 
00117     def pub_data(self, data):
00118         ''' Given data, interpret into Joy message and publish
00119         '''
00120         do_publish = False
00121         self.msg.header.stamp = rospy.Time.now()
00122         for event in data:
00123             control = event[0]
00124             
00125             
00126 
00127             
00128             if (control[0] & 0xF0) == 176:
00129                 control_id = control[1] | ((control[0] & 0x0F) << 8)
00130 
00131                 control_axis = self.modes[self.mode]['control_axis']
00132                 control_buttons = self.modes[self.mode]['control_buttons']
00133 
00134                 if control_id in control_axis:
00135                     if self.center_axis:
00136                         control_val = self.clip(-1.0, 1.0,
00137                                                 float(control[2] - 63) / 63.0)
00138                     else:
00139                         control_val = self.clip(0.0, 1.0,
00140                                                 float(control[2]) / 127)
00141 
00142                     axis = control_axis.index(control_id)
00143                     self.msg.axes[axis] = control_val
00144                     do_publish = True
00145 
00146                 if control_id in control_buttons:
00147                     button = control_buttons.index(control_id)
00148                     if control[2] != 0:
00149                         self.msg.buttons[button] = 1
00150                     else:
00151                         self.msg.buttons[button] = 0
00152                     do_publish = True
00153 
00154             
00155             elif control[0] == 79:
00156                 self.set_mode(control[1])
00157                 do_publish = True
00158 
00159         if do_publish:
00160             self.pub.publish(self.msg)