korg.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 #
00003 # joystick input driver for Korg NanoKontrol input device
00004 #
00005 # Author: Austin Hendrix
00006 # Author: Allison Thackston
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         # load in default parameters if not set
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         # determine how axis should be interpreted
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             # look for continuous controller commands
00089             if (control[0] & 0xF0) == 176:
00090                 control_id = control[1] | ((control[0] & 0x0F) << 8)
00091 
00092                 # guess initial mode based on command
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             # @todo use timestamp from msg
00125             # timestamp = event[1]
00126 
00127             # look for continuous controller commands
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             # look for mode commands
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)


korg_nanokontrol
Author(s): Austin Hendrix, Allison Thackston
autogenerated on Thu Jun 6 2019 20:12:12