update_robot.py
Go to the documentation of this file.
00001 #!/usr/bin/python2
00002 
00003 # Copyright (c) 2013-2014, Rethink Robotics
00004 # All rights reserved.
00005 #
00006 # Redistribution and use in source and binary forms, with or without
00007 # modification, are permitted provided that the following conditions are met:
00008 #
00009 # 1. Redistributions of source code must retain the above copyright notice,
00010 #    this list of conditions and the following disclaimer.
00011 # 2. Redistributions in binary form must reproduce the above copyright
00012 #    notice, this list of conditions and the following disclaimer in the
00013 #    documentation and/or other materials provided with the distribution.
00014 # 3. Neither the name of the Rethink Robotics nor the names of its
00015 #    contributors may be used to endorse or promote products derived from
00016 #    this software without specific prior written permission.
00017 #
00018 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00019 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00020 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00021 # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00022 # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00023 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00024 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00025 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00026 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00027 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00028 # POSSIBILITY OF SUCH DAMAGE.
00029 
00030 import errno
00031 import argparse
00032 import os
00033 import sys
00034 
00035 import rospy
00036 
00037 import std_msgs.msg
00038 
00039 import baxter_dataflow
00040 
00041 from baxter_maintenance_msgs.msg import (
00042     UpdateSources,
00043     UpdateStatus,
00044 )
00045 
00046 
00047 class Updater(object):
00048     """
00049     Control the updater on the robot.
00050 
00051     Signals:
00052         status_changed:     Fired when the update status changes.  Passes
00053                             the current UpdateStatus message.
00054     """
00055     def __init__(self):
00056         self.status_changed = baxter_dataflow.Signal()
00057 
00058         self._status = UpdateStatus()
00059         self._avail_updates = UpdateSources()
00060 
00061         self._update_sources = rospy.Subscriber(
00062             '/usb/update_sources',
00063             UpdateSources,
00064             self._on_update_sources)
00065 
00066         self._updater_status_sub = rospy.Subscriber(
00067             '/updater/status',
00068             UpdateStatus,
00069             self._on_update_status)
00070 
00071         self._updater_start = rospy.Publisher(
00072             '/updater/start',
00073             std_msgs.msg.String)
00074 
00075         self._updater_stop = rospy.Publisher(
00076             '/updater/stop',
00077             std_msgs.msg.Empty)
00078 
00079         baxter_dataflow.wait_for(
00080             lambda: self._avail_updates.uuid != '',
00081             timeout=5.0,
00082             timeout_msg="Failed to get list of available updates"
00083         )
00084 
00085     def _on_update_sources(self, msg):
00086         if msg.uuid != self._avail_updates.uuid:
00087             self._avail_updates = msg
00088 
00089     def _on_update_status(self, msg):
00090         if self._status != msg:
00091             self._status = msg
00092             self.status_changed(msg)
00093 
00094     def list(self):
00095         """
00096         Return a list of tuples (version, uuid) of all available updates
00097         """
00098         return [(u.version, u.uuid) for u in self._avail_updates.sources]
00099 
00100     def command_update(self, uuid):
00101         """
00102         Command the robot to launch the update with the given uuid.
00103 
00104         @param uuid: uuid of the update to start.
00105         """
00106         if not any([u.uuid == uuid for u in self._avail_updates.sources]):
00107             raise OSError(errno.EINVAL, "Invalid update uuid '%s'" % (uuid,))
00108 
00109         self._updater_start.publish(std_msgs.msg.String(uuid))
00110 
00111     def stop_update(self):
00112         """
00113         Stop the current update process, if any.
00114         """
00115         self._updater_stop.publish()
00116 
00117 
00118 def run_update(updater, uuid):
00119     """
00120     Run and monitor the progress of an update.
00121 
00122     @param updater: Instance of Updater to use.
00123     @param uuid: update uuid.
00124     """
00125 
00126     # Work around lack of a nonlocal keyword in python 2.x
00127     class NonLocal(object):
00128         pass
00129 
00130     nl = NonLocal
00131     nl.rc = 1
00132     nl.done = False
00133 
00134     def on_update_status(msg):
00135         if msg.status == UpdateStatus.STS_IDLE:
00136             nl.done = True
00137         elif msg.status == UpdateStatus.STS_INVALID:
00138             print ("Invalid update uuid, '%s'." % (uuid,))
00139             nl.done = True
00140         elif msg.status == UpdateStatus.STS_BUSY:
00141             print ("Update already in progress (may be shutting down).")
00142             nl.done = True
00143         elif msg.status == UpdateStatus.STS_CANCELLED:
00144             print ("Update cancelled.")
00145             nl.done = True
00146         elif msg.status == UpdateStatus.STS_ERR:
00147             print ("Update failed: %s." % (msg.long_description,))
00148             nl.done = True
00149             nl.rc = 1
00150         elif msg.status == UpdateStatus.STS_LOAD_KEXEC:
00151             print ("Robot will now reboot to finish updating...")
00152             nl.rc = 0
00153         else:
00154             print ("Updater:  %s" % (msg.long_description))
00155 
00156     def on_shutdown():
00157         updater.stop_update()
00158     rospy.on_shutdown(on_shutdown)
00159 
00160     updater.status_changed.connect(on_update_status)
00161 
00162     try:
00163         updater.command_update(uuid)
00164     except OSError, e:
00165         if e.errno == errno.EINVAL:
00166             print e.strerror
00167             return 1
00168         raise
00169 
00170     try:
00171         baxter_dataflow.wait_for(
00172             lambda: nl.done == True,
00173             timeout=5 * 60,
00174             timeout_msg="Timeout waiting for update to succeed"
00175         )
00176     except Exception, e:
00177         if not (hasattr(e, 'errno') and e.errno == errno.ESHUTDOWN):
00178             print e.strerror
00179         nl.rc = 1
00180 
00181     return nl.rc
00182 
00183 
00184 def main():
00185     parser = argparse.ArgumentParser()
00186     required = parser.add_mutually_exclusive_group(required=True)
00187     required.add_argument('-l', '--list', action='store_const',
00188                           dest='cmd', const='list', default='update',
00189                           help="List available updates and UUID's")
00190     required.add_argument('-u', '--update', dest='uuid', default='',
00191                           help='Launch the given update')
00192     args = parser.parse_args(rospy.myargv()[1:])
00193     cmd = args.cmd
00194     uuid = args.uuid
00195 
00196     rospy.init_node('rsdk_update_robot')
00197     updater = Updater()
00198 
00199     if cmd == 'list':
00200         updates = updater.list()
00201         if not len(updates):
00202             print ("No available updates")
00203         else:
00204             print ("%-30s%s" % ("Version", "UUID"))
00205             for update in updates:
00206                 print("%-30s%s" % (update[0], update[1]))
00207         return 0
00208     elif cmd == 'update':
00209         if uuid == '':
00210             print "Error:  no update uuid specified"
00211             return 1
00212         msg = ("NOTE: Please plug in any Rethink Electric Parallel Grippers\n"
00213                "      into the robot now, so that the Gripper Firmware\n"
00214                "      can be automatically upgraded with the robot.\n")
00215         print (msg)
00216         raw_input("Press <Enter> to Continue...")
00217         if rospy.is_shutdown():
00218             return 0
00219         return run_update(updater, uuid)
00220 
00221 if __name__ == '__main__':
00222     sys.exit(main())


baxter_tools
Author(s): Rethink Robotics Inc.
autogenerated on Sun Oct 5 2014 22:29:27