pipette_node.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 
00003 # Software License Agreement (BSD License)
00004 #
00005 # Copyright (c) 2010, Willow Garage, Inc.
00006 # All rights reserved.
00007 #
00008 # Redistribution and use in source and binary forms, with or without
00009 # modification, are permitted provided that the following conditions
00010 # are met:
00011 #
00012 #  * Redistributions of source code must retain the above copyright
00013 #    notice, this list of conditions and the following disclaimer.
00014 #  * Redistributions in binary form must reproduce the above
00015 #    copyright notice, this list of conditions and the following
00016 #    disclaimer in the documentation and/or other materials provided
00017 #    with the distribution.
00018 #  * Neither the name of Willow Garage, Inc. nor the names of its
00019 #    contributors may be used to endorse or promote products derived
00020 #    from this software without specific prior written permission.
00021 #
00022 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00023 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00024 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00025 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00026 # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00027 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00028 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00029 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00030 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00032 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00033 # POSSIBILITY OF SUCH DAMAGE.
00034 
00035 import roslib ; roslib.load_manifest('pipette_driver')
00036 import rospy
00037 import pipette_driver
00038 from pipette_driver.srv import PipetteAction, PipetteActionRequest, PipetteActionResponse
00039 from diagnostic_msgs.msg import DiagnosticStatus, DiagnosticArray, KeyValue
00040 
00041 import sys
00042 import getopt
00043 import threading
00044 from collections import defaultdict
00045 
00046 _default_bd_addr = "00:80:98:e6:2b:30"    
00047 
00048 """
00049 usage: %(progname)s [-h] [-a <bd_address]
00050   Driver node for Viaflo Vision Pipette.  
00051   Will proform actions based on service calls.
00052  
00053   Options:
00054   -h : show this help
00055   -a : bluetooth address of pipette.  Uses %(default_bd_addr)s as default
00056 """
00057 
00058 def usage():
00059     global default_bd_address
00060     doc_args = {'progname':sys.argv[0], 'default_bd_addr':_default_bd_addr}
00061     print __doc__ % doc_args
00062 
00063 
00064 class PipetteNode(object):
00065     def __init__(self, bd_addr):
00066         print 'Opening pipette'
00067         port = 1
00068         pipette = pipette_driver.ViafloPipette()
00069         pipette.open(bd_addr, port)
00070         print 'Requesting info'
00071         cmd = pipette_driver.ViafloInfoCommand()
00072         self.pipette_info = pipette.send_msg(cmd)
00073         print 'Requesting version'
00074         cmd = pipette_driver.ViafloVersionCommand()
00075         self.pipette_version = pipette.send_msg(cmd)
00076         print 'Requesting position'
00077         cmd = pipette_driver.ViafloPositionQueryCommand()
00078         self.pipette_position = resp = pipette.send_msg(cmd).pipette_stop
00079         self.last_action = PipetteActionRequest.QUERY
00080 
00081         self.diag_pub = rospy.Publisher('/diagnostics', DiagnosticArray)
00082         self.level = DiagnosticStatus.OK
00083         self.message = "OK"
00084         self.bd_addr = bd_addr
00085         self.pipette = pipette
00086         self.quit = False
00087 
00088         # Lock allows sharing between diagnostics thread and sevice callback
00089         self.lock = threading.Lock()
00090         # These are the values that the lock protects:
00091         #   pipette_position
00092         #   state
00093         #   msg
00094         # These value are used only by diagnostics:
00095         #   pipette_info
00096         #   pipette_version
00097         #   bd_addr
00098         # These values are used only by callback:
00099         #   pipette        
00100 
00101         # Start diagnostics thread
00102         self.diagnostic_thread = threading.Thread(None, self.publish_diagnostics)    
00103         self.diagnostic_thread.start()
00104         srv = rospy.Service('pipette_action', PipetteAction, self.pipette_action_callback)
00105         
00106     def stop(self):
00107         print "Stopping diagnostics"
00108         self.quit = True
00109         self.diagnostic_thread.join()
00110 
00111     def publish_diagnostics(self):
00112         print "Diagnostics start"
00113         r = rospy.Rate(1) #1Hz
00114         action_dict = defaultdict(lambda : "???", {1:'Query', 2:'Purge', 3:'Aspirate', 4:'Dispense'})
00115         while not self.quit and not rospy.is_shutdown():
00116             with self.lock:
00117                 pipette_position = self.pipette_position
00118                 level = self.level
00119                 message = self.message
00120                 last_action = self.last_action
00121             kv = []
00122             kv.append( KeyValue('Position (uL)', str(pipette_position)))
00123             kv.append( KeyValue('Last Action',   "%s (%d)" % (action_dict[last_action], last_action)))
00124             name = "Viaflo Pipette (%s)" % self.bd_addr
00125             hardware_id = self.pipette_info.serial
00126             d = DiagnosticStatus(level, name, message, hardware_id, kv)
00127             h = roslib.msg.Header()
00128             h.stamp = rospy.Time.now()
00129             s = DiagnosticArray(h, [d])
00130             self.diag_pub.publish(s)
00131             r.sleep()
00132         print "Diagnostics stop"            
00133 
00134     def pipette_action_callback(self, req):
00135         print "Action callback"
00136         action = req.action
00137         if action==req.PURGE:
00138             cmd = pipette_driver.ViafloPurgeCommand(req.speed,req.bells)
00139         elif action==req.DISPENSE:
00140             cmd = pipette_driver.ViafloDispenseCommand(req.speed,req.amount,req.bells)
00141         elif action==req.ASPIRATE:
00142             cmd = pipette_driver.ViafloAspirateCommand(req.speed,req.amount,req.bells)
00143         else:
00144             raise RuntimeError("Invalid action (%d)" % action)
00145         
00146         try:
00147             pipette_position = self.pipette.send_msg(cmd).pipette_stop
00148         except Exception,e:
00149             with self.lock:
00150                 self.level = DiagnosticStatus.ERROR
00151                 self.message = str(e)
00152             raise
00153 
00154         # Update pipette diagnostics
00155         with self.lock:
00156             self.level = DiagnosticStatus.OK
00157             self.messge = "OK"
00158             self.pipette_position = pipette_position
00159             self.last_action = action
00160 
00161         return PipetteActionResponse(pipette_position)
00162 
00163 
00164 def main():
00165     rospy.init_node('pipette_node')
00166     argv = rospy.myargv(argv=sys.argv)
00167 
00168     # Default values
00169     port = 1
00170     bd_addr = _default_bd_addr
00171 
00172     progname = argv[0]
00173     optlist, args = getopt.getopt(argv[1:], "ha:", ["help","address="])
00174     for opt,val in optlist:
00175         if opt=='--help' or opt=='-h':
00176             usage()
00177             return
00178         elif opt=='--address' or opt=='-a':
00179             bd_addr = val
00180         else:
00181             print "Invalid option '%s'"%field
00182             sys.exit(1)
00183 
00184     print "Usage bluetooth address : %s" % bd_addr
00185     p = PipetteNode(bd_addr)    
00186     rospy.spin()
00187     p.stop()
00188     
00189 
00190 if __name__ == "__main__":
00191     main()
00192     
00193 


pipette_driver
Author(s): Kevin Watts
autogenerated on Tue Dec 10 2013 15:49:44