Esempio n. 1
0
def workspace_plot(outfile='highdim_workspace.png'):
    '''Plot planar workspace for the high-dimensional case study.'''
    # define boundary: unit hypercube
    boundary = BoxBoundary([[0, 1], [0, 1]])
    # define boundary style
    boundary.style = {'color': 'black'}
    # create robot's workspace
    wspace = Workspace(boundary=boundary)

    # create robot object
    initConf = Point2D((0.1, 0.1))  # start close to the origin
    robot = FullyActuatedRobot('Robot-highdim', init=initConf, wspace=wspace)
    robot.diameter = 0

    # create simulation object
    sim = Simulate2D(wspace, robot, None)

    # regions of interest
    R1 = (BoxRegion2D([[.00, .20], [.00, .20]], ['r1']), 'brown')
    R2 = (BoxRegion2D([[.25, .40], [.40, .55]], ['r2']), 'green')
    R3 = (BoxRegion2D([[.70, 1.00], [.40, .60]], ['r3']), 'red')
    R4 = (BoxRegion2D([[.00, .50], [.90, 1.00]], ['r4']), 'magenta')
    # global obstacles
    O1 = (BoxRegion2D([[.20, .30], [.30, .35]], ['o1']), 'gray')
    O2 = (BoxRegion2D([[.15, .20], [.40, .60]], ['o2']), 'gray')
    O3 = (BoxRegion2D([[.50, .55], [.30, .80]], ['o3']), 'gray')
    # local obstacles
    L1 = (BoxRegion2D([[.45, .50], [.75, .80]], ['LO']), to_rgba('gray', .6))
    L2 = (BoxRegion2D([[.90, 1.00], [.50, .55]], ['LO']), to_rgba('gray', .6))
    L3 = (BoxRegion2D([[.75, .80], [.20, .25]], ['LO']), to_rgba('gray', .6))

    # add all regions
    regions = [R1, R2, R3, R4, O1, O2, O3, L1, L2, L3]

    # add regions to workspace
    for r, c in regions:
        # add styles to region
        addStyle(r, style={'facecolor': c})
        r.textStyle['fontsize'] = 24
        # add region to workspace
        sim.workspace.addRegion(r)

    # set the robot's sensor
    sensingShape = BallBoundary([0, 0], 0.001)
    robot.sensor = BoundingBoxSimulatedSensor(robot, sensingShape, [], [])

    # display workspace
    sim.display(save=outfile, figsize=(7, 7))
Esempio n. 2
0
def postprocessing(logfilename,
                   ts_filename,
                   outdir,
                   lts_index,
                   rrg_iterations,
                   lts_iterations,
                   local_traj_iterations,
                   generate=()):
    '''Parses log file and generate statistics and figures.'''

    if not os.path.isdir(outdir):
        os.makedirs(outdir)

    with open(logfilename, 'r') as logfile:
        # first process general data
        data = dict()
        line = ''
        for line in logfile:
            prefix, line_data = line.split('--')
            if prefix.lower().rfind('info') >= 0:
                data.update(eval(line_data))
                if line_data.lower().find('start global planning') >= 0:
                    break
        print 'general data:', len(data)

        # second process data on global planner
        rrg_data = []
        iteration_data = None
        for line in logfile:
            prefix, line_data = line.split('--')
            if prefix.lower().rfind('info') >= 0:
                if line_data.lower().rfind('found solution') >= 0:
                    rrg_data.append(iteration_data)
                    break
                if line_data.lower().find('iteration') >= 0:
                    if iteration_data is not None:
                        rrg_data.append(iteration_data)
                    iteration_data = dict()
                iteration_data.update(eval(line_data))
        print 'rrg data:', len(rrg_data)

        rrg_stat_data = eval(line_data)
        for line in logfile:
            prefix, line_data = line.split('--')
            if prefix.lower().rfind('info') >= 0:
                if line_data.lower().find('end global planning') >= 0:
                    break
                rrg_stat_data.update(eval(line_data))
        print 'rrg_stat_data', len(rrg_stat_data)

        assert rrg_stat_data['Iterations'] == len(rrg_data)

        # third process data on local planner
        rrt_stat_data = dict()
        for line in logfile:
            prefix, line_data = line.split('--')
            if prefix.lower().rfind('info') >= 0:
                if line_data.lower().find('initialize local planner') >= 0:
                    break
                rrt_stat_data.update(eval(line_data))
        print 'rrt_stat_data:', len(rrt_stat_data)

        rrt_data = []
        execution_data = dict()
        for line in logfile:
            prefix, line_data = line.split('--')
            if prefix.lower().rfind('info') >= 0:
                if line_data.lower().find(
                        'local online planning finished') >= 0:
                    rrt_data.append(execution_data)
                    break
                # NOTE: second condition is for compatibility with Cozmo logs
                if (line_data.lower().find('start local planning step') >= 0
                        or line_data.lower().find('plan start time') >= 0):
                    rrt_data.append(execution_data)
                    execution_data = dict()
                execution_data.update(eval(line_data))
        print 'rrt data:', len(rrt_data)

    # save useful information
    with open(os.path.join(outdir, 'general_data.txt'), 'w') as f:
        for key in [
                'Robot initial configuration', 'Robot step size',
                'Global specification', 'Buchi size', 'Local specification'
        ]:
            print >> f, key, ':', data[key]

        for key in [
                'Iterations', 'global planning runtime', 'Size of TS',
                'Size of PA'
        ]:
            print >> f, key, ':', rrg_stat_data[key]
        pre, suff = rrg_stat_data['global policy']
        print >> f, 'Global policy size :', (len(pre), len(suff))

        # key = 'Computing potential function runtime'
        # print>>f, key, ':', rrt_stat_data[key]

    # get workspace
    wspace, style = data['Workspace']
    wspace.boundary.style = style
    ewspace, style = data['Expanded workspace']
    ewspace.boundary.style = style

    # get robot
    robot_name = data['Robot name']
    initConf = data['Robot initial configuration']
    stepsize = data['Robot step size']
    robot = eval(data['Robot constructor'])
    robot.diameter = data['Robot diameter']
    robot.localObst = data['Local obstacle label']

    # create simulation object
    sim = Simulate2D(wspace, robot, ewspace)
    sim.config['output-dir'] = outdir

    # add regions to workspace
    for key, value in data.iteritems():
        if isinstance(key, tuple) and key[0] == "Global region":
            r, style = value
            # add styles to region
            addStyle(r, style=style)
            # add region to workspace
            sim.workspace.addRegion(r)
            # create expanded region
            er = expandRegion(r, robot.diameter / 2)
            # add style to the expanded region
            addStyle(er, style=style)
            # add expanded region to the expanded workspace
            sim.expandedWorkspace.addRegion(er)

    # get local requests and obstacles
    localSpec = data['Local specification']
    requests = []
    obstacles = []
    for key, value in data.iteritems():
        if isinstance(key, tuple) and key[0] == "Local region":
            r, style, path, is_request = value
            # add styles to region
            addStyle(r, style=style)
            # add path
            if path:
                r.path = it.cycle(path)
                r.original_path = path[:]
            # add to requests or obstacles lists
            if is_request:
                name = next(iter(r.symbols))
                requests.append(Request(r, name, localSpec[name]))
            else:
                obstacles.append(r)

    # get robot sensor
    robot.sensor = eval(data['Robot sensor constructor'])

    # create RRG planner and load transition system, and global policy
    sim.offline = RRGPlanner(robot, None, 1)
    prefix, suffix = rrg_stat_data['global policy']
    sim.solution = (prefix, suffix[1:])
    print 'Global policy size:', len(prefix), len(suffix)

    if any(option in generate for option in ('workspace', 'expanded workspace',
                                             'global solution')):
        # set larger font for saving figures
        for r in sim.workspace.regions | sim.expandedWorkspace.regions:
            r.fontsize_orig = r.textStyle.get('fontsize', 12)
            r.textStyle['fontsize'] = 24

        # display workspace
        if 'workspace' in generate:
            sim.display(save='workspace.png')
        # display expanded workspace
        if 'expanded workspace' in generate:
            sim.display(expanded=True, save='eworkspace.png')
        # display solution for off-line problem
        if 'global solution' in generate:
            ts = sim.offline.ts
            sim.offline.ts = Ts.load(ts_filename)
            sim.display(expanded=True,
                        solution=prefix + suffix[1:],
                        save='global_solution.png')
            sim.offline.ts = ts

        # restore original fontsize
        for r in sim.workspace.regions:
            r.textStyle['fontsize'] = r.fontsize_orig
            del r.fontsize_orig

    # display both workspaces
    if 'both workspaces' in generate:
        sim.display(expanded='both')

    # show construction of rrg
    sim.offline.ts.init[initConf] = 1
    if 'RRG construction' in generate:
        sim.config['global-ts-color'] = {
            'node_color': 'blue',
            'edge_color': 'black'
        }
        sim.config['video-interval'] = 500
        sim.config['video-file'] = 'rrg_construction.mp4'
        sim.save_rrg_process(rrg_data)
        # reset to default colors
        sim.defaultConfiguration(reset=['global-ts-color'])

    if 'RRG iterations' in generate:
        sim.config['global-ts-color'] = {
            'node_color': 'blue',
            'edge_color': 'black'
        }
        rrg_iterations = [
            i + (i == -1) * (len(rrg_data) + 1) for i in rrg_iterations
        ]
        sim.save_rrg_iterations(rrg_data, rrg_iterations)
        # reset to default colors
        sim.defaultConfiguration(reset=['global-ts-color'])

    # set to global and to save animation
    sim.offline.ts = Ts.load(ts_filename)
    print 'TS size', sim.offline.ts.size()
    if 'offline plan' in generate:
        sim.config['video-interval'] = 30
        sim.config['sim-step'] = 0.02
        sim.config['video-file'] = 'global_plan.mp4'
        sim.simulate(loops=1, offline=True)
        sim.play(output='video', show=False)
        sim.save()

    # get online trajectory
    sim.offline.ts = Ts.load(ts_filename)
    trajectory = [d['new configuration'] for d in rrt_data]
    local_plans = [d['local plan'] for d in rrt_data] + [[]]
    potential = [d['potential'] for d in rrt_data] + [0]
    requests = [d['requests'] for d in rrt_data] + [[]]
    print len(trajectory), len(local_plans)

    if 'trajectory' in generate:
        # set larger font for saving figures
        for r in sim.workspace.regions | sim.expandedWorkspace.regions:
            r.fontsize_orig = r.textStyle.get('fontsize', 12)
            r.textStyle['fontsize'] = 24

        sim.config['trajectory-min-transparency'] = 0.2  # fading
        sim.config['trajectory-history-length'] = len(
            trajectory)  # full history
        sim.config['global-policy-color'] = 'orange'

        sim.online = LocalPlanner(None, sim.offline.ts, robot, localSpec)
        sim.online.trajectory = trajectory
        sim.online.robot.sensor.requests = []
        sim.display(expanded=True,
                    solution=prefix + suffix[1:],
                    show_robot=False,
                    localinfo=('trajectory', ),
                    save='trajectory.png')
        sim.defaultConfiguration(reset=[
            'trajectory-min-transparency', 'trajectory-history-length',
            'global-policy-color'
        ])

        # restore original fontsize
        for r in sim.workspace.regions:
            r.textStyle['fontsize'] = r.fontsize_orig
            del r.fontsize_orig

    # local plan visualization
    sim.online = LocalPlanner(None, sim.offline.ts, robot, localSpec)
    sim.online.trajectory = trajectory
    if 'online plan' in generate:
        sim.config['video-interval'] = 30
        sim.config['sim-step'] = 0.01
        sim.config['video-file'] = 'local_plan.mp4'
        sim.simulate(offline=False)
        sim.play(output='video',
                 show=False,
                 localinfo={
                     'trajectory': trajectory,
                     'plans': local_plans,
                     'potential': potential,
                     'requests': requests
                 })
        sim.save()

    if 'online trajectory iterations' in generate:
        sim.config['sim-step'] = 0.05
        sim.config['trajectory-min-transparency'] = 1.0  # no fading
        sim.config['trajectory-history-length'] = 100000  # entire history
        sim.config['image-file-template'] = 'local_trajectory_{frame:04d}.png'
        sim.config['global-policy-color'] = 'orange'
        # simulate and save
        sim.simulate(offline=False)
        sim.play(output='plots',
                 show=False,
                 localinfo={
                     'trajectory': trajectory,
                     'plans': local_plans,
                     'potential': potential,
                     'requests': requests
                 })
        sim.save(output='plots', frames=local_traj_iterations)
        # set initial values
        sim.defaultConfiguration(reset=[
            'trajectory-min-transparency', 'trajectory-history-length',
            'image-file-template', 'global-policy-color'
        ])

    msize = np.mean([d['tree size'] for d in rrt_data if d['tree size'] > 0])
    print 'Mean size:', msize
    for k, d in enumerate(rrt_data):
        if d['tree size'] > 0:
            print(k, d['tree size'])

    if any(option in generate
           for option in ('LTS iterations', 'LTS construction')):
        idx = lts_index
        print rrt_data[idx]['tree size']
        print 'current state:', rrt_data[idx - 1]['new configuration']

        lts_data = sorted([
            v for k, v in rrt_data[idx].items()
            if str(k).startswith('lts iteration')
        ],
                          key=lambda x: x[0])
        #     print lts_data

        sim.online.lts = Ts(directed=True, multi=False)
        sim.online.lts.init[rrt_data[idx - 1]['new configuration']] = 1
        # reset and fast-forward requests' locations
        for r in sim.robot.sensor.all_requests:
            aux = it.cycle(r.region.original_path)
            for _ in range(idx - 1):
                r.region.translate(next(aux))
        sim.robot.sensor.requests = [
            r for r in sim.robot.sensor.all_requests
            if r in rrt_data[idx]['requests']
        ]
        if 'LTS construction' in generate:
            sim.config['video-interval'] = 500
            sim.config['video-file'] = 'lts_construction.mp4'
            sim.save_lts_process(lts_data, endframe_hold=20)

        if 'LTS iterations' in generate:
            lts_iterations = [
                i + (i == -1) * len(lts_data) for i in lts_iterations
            ]
            sim.save_lts_iterations(lts_data, lts_iterations)

    if 'LTS statistics' in generate:
        metrics = [('tree size', True), ('local planning runtime', False),
                   ('local planning execution', False)]
        rrt_data = rrt_data[1:]
        # NOTE: This is for compatibility with the Cozmo logs
        if 'local planning execution' not in rrt_data[0]:
            for d in rrt_data:
                duration = (d['plan stop time'] - d['plan start time']) * 1000
                d['local planning execution'] = duration

        data = [len(d['requests']) for d in rrt_data]
        serviced = sum(n1 - n2 for n1, n2 in it.izip(data, data[1:])
                       if n1 > n2)

        with open(os.path.join(outdir, 'local_performance_stats.txt'),
                  'w') as f:
            print >> f, 'no trials:', len(rrt_data)
            print >> f, 'no requests serviced', serviced
            ops = [np.mean, np.min, np.max, np.std]
            for key, positive in metrics:
                if positive:
                    print >> f, key, [
                        op([
                            trial[key] for trial in rrt_data if trial[key] > 0
                        ]) for op in ops
                    ]
                else:
                    print >> f, key, [
                        op([trial[key] for trial in rrt_data]) for op in ops
                    ]
Esempio n. 3
0
def define_problem(outputdir='.'):
    '''Define case study setup (robot parameters, workspace, etc.).'''

    # define robot diameter (used to compute the expanded workspace)
    robotDiameter = 0.5

    # define boundary
    boundary = BoxBoundary2D([[0, 30], [0, 30]])
    # define boundary style
    boundary.style = {'color': 'black'}
    # create expanded region
    eboundary = BoxBoundary2D(boundary.ranges +
                              np.array([[1, -1], [1, -1]]) * robotDiameter / 2)
    eboundary.style = {'color': 'black'}

    # create robot's workspace and expanded workspace
    wspace = Workspace(boundary=boundary)
    ewspace = Workspace(boundary=eboundary)

    # create robot object
    robot = FullyActuatedRobot('Drone',
                               init=Point2D((2, 2)),
                               wspace=ewspace,
                               stepsize=5.999)
    robot.diameter = robotDiameter
    robot.localObst = 'local_obstacle'

    logging.info('"Workspace": (%s, %s)', wspace, boundary.style)
    logging.info('"Expanded workspace": (%s, %s)', ewspace, eboundary.style)
    logging.info('"Robot name": "%s"', robot.name)
    logging.info('"Robot initial configuration": %s', robot.initConf)
    logging.info('"Robot step size": %f', robot.controlspace)
    logging.info('"Robot diameter": %f', robot.diameter)
    logging.info(
        '"Robot constructor": "%s"',
        'FullyActuatedRobot(robot_name, init=initConf, wspace=ewspace, '
        'stepsize=stepsize)')
    logging.info('"Local obstacle label": "%s"', robot.localObst)

    # create simulation object
    sim = Simulate2D(wspace, robot, ewspace)
    sim.config['output-dir'] = outputdir

    regions = []
    #### add trucks ####
    L = 8.0
    W = 2.0
    box = np.array([[-L / 2, L / 2], [-W / 2, W / 2]])
    ntrucks = 4
    for i in range(ntrucks):
        # left array of trucks
        lc = np.array([[7, 8.75 + i * 4.]]).T
        regions.append((BoxRegion2D(lc + box, ['tl{}'.format(i)]), 'brown'))
        # right array of trucks
        rc = np.array([[23, 8.75 + i * 4.]]).T
        regions.append((BoxRegion2D(rc + box, ['tr{}'.format(i)]), 'brown'))

    #### add missiles ####
    mc = np.array([[15.0, 15.0]]).T
    mL = 2.5
    mW = 16
    box = np.array([[-mL / 2, mL / 2], [-mW / 2, mW / 2]])
    regions.append((BoxRegion2D(mc + box, ['missile']), 'red'))

    #### add charging stations ####
    cs_size = 1.0
    box = np.array([[-cs_size / 2, cs_size / 2], [-cs_size / 2, cs_size / 2]])
    cs_center = np.array([[10, 2]]).T
    regions.append((BoxRegion2D(cs_center + box, ['cs1']), 'blue'))
    cs_center = np.array([[20, 2]]).T
    regions.append((BoxRegion2D(cs_center + box, ['cs2']), 'blue'))

    # add regions to workspace
    for k, (r, c) in enumerate(regions):
        # add styles to region
        addStyle(r, style={'facecolor': c})
        # add region to workspace
        sim.workspace.addRegion(r)
        # create expanded region
        er = expandRegion(r, robot.diameter / 2)
        # add style to the expanded region
        addStyle(er, style={'facecolor': c})
        # add expanded region to the expanded workspace
        sim.expandedWorkspace.addRegion(er)

        logging.info('("Global region", %d): (%s, %s)', k, r, r.style)


#     # local  requests
#     F1 = (BallRegion2D([3.24, 1.98], 0.3, ['fire']),
#           ([[3.24, 1.98], [2.54, 2.28], [3.5, 3], [4.02, 2.28]], 0.05),
#           ('orange', 0.5))
#     F2 = (BallRegion2D([1.26, 0.48], 0.18, ['fire']),
#           ([[1.26, 0.48], [1.1, 1.1], [1.74, 0.92], [0.6, 0.6]], 0.05),
#           ('orange', 0.5))
#     S2 = (BallRegion2D([4.32, 1.48], 0.27, ['survivor']),
#           ([[4.32, 1.48], [3.6, 1.2], [4, 2]], 0.05),
#           ('yellow', 0.5))
#     requests = [F1, F2, S2]
    requests = []
    # define local specification as a priority function
    localSpec = {'survivor': 0, 'fire': 1}
    logging.info('"Local specification": %s', localSpec)
    # local obstacles #FIXME: defined in expanded workspace not workspace
    obstacles = [
        (BoxRegion2D([[6.5, 7.5], [8, 9]],
                     ['LO']), ([[7.0, 8.5], [23.0, 8.5], [23.0, 20.5],
                                [7.0, 20.5]], 0.03), ('darkgray', 0.8)),
        (PolygonRegion2D([[15.0 + np.cos(phi), 5.0 + np.sin(phi)]
                          for phi in np.arange(0, 2 * np.pi, np.pi / 3)],
                         ['LO']), ([[15.0, 5.0],
                                    [15.0, 25.0]], 0.03), ('gray', 0.8)),
        (BallRegion2D([25, 22], 0.5,
                      ['LO']), ([[25.0, 22.0], [25.0, 8.0], [15.0, 5.0],
                                 [5.0, 8.0], [5.0, 22.0],
                                 [15.0, 25.0]], 0.03), ('darkgray', 0.8))
    ]

    # add style to local requests and obstacles
    for k, (r, path, c) in enumerate(requests + obstacles):
        # add styles to region
        addStyle(r, style={'facecolor': to_rgba(*c)})  #FIXME: HACK
        # create path
        r_path = path
        if path:
            wps, step = path
            wps = wps + [wps[0]]
            r.path = []
            for a, b in it.izip(wps[:-1], wps[1:]):
                r.path += line_translate(a, b, step)
            r_path = map(list, r.path)
            r.path = it.cycle(r.path)

        logging.info('("Local region", %d): (%s, %s, %s, %d)', k, r, r.style,
                     r_path, k < len(requests))

    # create request objects
    reqs = []
    for r, _, _ in requests:
        name = next(iter(r.symbols))
        reqs.append(Request(r, name, localSpec[name]))
    requests = reqs
    obstacles = [o for o, _, _ in obstacles]

    # set the robot's sensor
    sensingShape = BallBoundary2D([0, 0], robot.diameter * 2.5)
    robot.sensor = SimulatedSensor(robot, sensingShape, requests, obstacles)

    logging.info(
        '"Robot sensor constructor": "%s"',
        'SimulatedSensor(robot, BallBoundary2D([0, 0], robot.diameter*2.5),'
        'requests, obstacles)')

    # display workspace
    sim.display()

    # display expanded workspace
    sim.display(expanded=True)

    # globalSpec = ('[] ( (<> r1) && (<> r2) && (<> r3) && (<> r4)'
    #               + ' && !(o1 || o2 || o3 || o4 ))')
    #     globalSpec = ('[] ( (<> tr0) && (<> tr1) && (<> tr2) && (<> tr3)  && (<> tr4)'
    #                   ' && (<> tl0) && (<> tl1) && (<> tl2) && (<> tl3)  && (<> tl4)'
    #                   ' && (<> missle) )')
    # spec_tr = ' && '.join(['(<> tr{})'.format(i) for i in range(ntrucks)])
    # spec_tl = ' && '.join(['(<> tl{})'.format(i) for i in range(ntrucks)])
    # globalSpec = '[] ( {} && {} && {})'.format(spec_tr, spec_tl, '(<> missile)')

    #globalSpec = '[] (<> (tl0 && <> (tl1 && <> (tl2 && <> ( tl3 && <> (tl4 && <> ( tr4 && <> ( tr4 && <> ( tr3 && <> (tr2 && <> ( tr1 && <> ( t0))))))))))))'

    #### this is the LTL global spec ####
    # globalSpec = '[] (<> (tl0 && <> (tl1 && <> (tl2 && <> ( tl3 && <>  (  tr3 && <> (tr2 && <> ( tr1 && <> ( tr0)))))))))'

    #### this is the TWTL global spec ####
    globalSpec = '[H^2 tl0]^[0, 500] | [H^2 tl1]^[0, 500]'

    logging.info('"Global specification": "%s"', globalSpec)

    return robot, sim, globalSpec, localSpec
Esempio n. 4
0
def define_problem(outputdir='.'):
    '''Define case study setup (robot parameters, workspace, etc.).'''

    # define robot diameter (used to compute the expanded workspace)
    robotDiameter = 0.36

    # define boundary
    boundary = BoxBoundary2D([[0, 4.8], [0, 3.6]])
    # define boundary style
    boundary.style = {'color' : 'black'}
    # create expanded region
    eboundary = BoxBoundary2D(boundary.ranges +
                                np.array([[1, -1], [1, -1]]) * robotDiameter/2)
    eboundary.style = {'color' : 'black'}

    # create robot's workspace and expanded workspace
    wspace = Workspace(boundary=boundary)
    ewspace = Workspace(boundary=eboundary)

    # create robot object
    robot = FullyActuatedRobot('Cozmo', init=Point2D((2, 2)), wspace=ewspace,
                               stepsize=0.999)
    robot.diameter = robotDiameter
    robot.localObst = 'local_obstacle'

    logging.info('"Workspace": (%s, %s)', wspace, boundary.style)
    logging.info('"Expanded workspace": (%s, %s)', ewspace, eboundary.style)
    logging.info('"Robot name": "%s"', robot.name)
    logging.info('"Robot initial configuration": %s', robot.initConf)
    logging.info('"Robot step size": %f', robot.controlspace)
    logging.info('"Robot diameter": %f', robot.diameter)
    logging.info('"Robot constructor": "%s"',
        'FullyActuatedRobot(robot_name, init=initConf, wspace=ewspace, '
        'stepsize=stepsize)')
    logging.info('"Local obstacle label": "%s"', robot.localObst)

    # create simulation object
    sim = Simulate2D(wspace, robot, ewspace)
    sim.config['output-dir'] = outputdir

    # regions of interest
    R1 = (BoxRegion2D([[0.45, 0.75], [0.45, 0.6]], ['r1']), 'brown')
    R2 = (BallRegion2D([3.9, 1.2], 0.3, ['r2']), 'green')
    R3 = (BoxRegion2D([[3.75, 4.05], [2.7, 3]], ['r3']), 'red')
    R4 = (PolygonRegion2D([[1.2 , 2.85], [0.9 , 3.15], [0.6 , 2.85],
                           [0.9 , 2.55], [1.2 , 2.55]], ['r4']), 'magenta')
    # global obstacles
    O1 = (BallRegion2D([2.4, 1.5], 0.36, ['o1']), 'gray')
    O2 = (PolygonRegion2D([[0.45, 1.2], [1.05, 1.5], [0.45, 1.8]], ['o2']),
          'gray')
    O3 = (PolygonRegion2D([[2.1, 2.7], [2.4, 3], [2.7, 2.7]], ['o3']), 'gray')
    O4 = (BoxRegion2D([[1.65, 1.95], [0.45, 0.6]], ['o4']), 'gray')

    # add all regions
    regions = [R1, R2, R3, R4, O1, O2, O3, O4]

    # add regions to workspace
    for k, (r, c) in enumerate(regions):
        # add styles to region
        addStyle(r, style={'facecolor': c})
        # add region to workspace
        sim.workspace.addRegion(r)
        # create expanded region
        er = expandRegion(r, robot.diameter/2)
        # add style to the expanded region
        addStyle(er, style={'facecolor': c})
        # add expanded region to the expanded workspace
        sim.expandedWorkspace.addRegion(er)

        logging.info('("Global region", %d): (%s, %s)', k, r, r.style)

    # local  requests
    F1 = (BallRegion2D([3.24, 1.98], 0.3, ['fire']),
          ([[3.24, 1.98], [2.54, 2.28], [3.5, 3], [4.02, 2.28]], 0.05),
          ('orange', 0.5))
    F2 = (BallRegion2D([1.26, 0.48], 0.18, ['fire']),
          ([[1.26, 0.48], [1.1, 1.1], [1.74, 0.92], [0.6, 0.6]], 0.05),
          ('orange', 0.5))
    S2 = (BallRegion2D([4.32, 1.48], 0.27, ['survivor']),
          ([[4.32, 1.48], [3.6, 1.2], [4, 2]], 0.05),
          ('yellow', 0.5))
    requests = [F1, F2, S2]
    # define local specification as a priority function
    localSpec = {'survivor': 0, 'fire': 1}
    logging.info('"Local specification": %s', localSpec)
    # local obstacles #FIXME: defined in expanded workspace not workspace
    obstacles = [(BoxRegion2D([[3, 3.5], [2, 2.5]], ['LO']), None,
                  ('gray', 0.8)),
                 (PolygonRegion2D([[3.2, 1.4], [3, 0.8], [3.4, 0.7]], ['LO']),
                  None, ('gray', 0.8)),
                 (BallRegion2D([1.6, 2.1], 0.15, ['LO']), None, ('gray', 0.8))]

    # add style to local requests and obstacles
    for k, (r, path, c) in enumerate(requests + obstacles):
        # add styles to region
        addStyle(r, style={'facecolor': to_rgba(*c)}) #FIXME: HACK
        # create path
        r_path = path
        if path:
            wps, step = path
            wps = wps + [wps[0]]
            r.path = []
            for a, b in it.izip(wps[:-1], wps[1:]):
                r.path += line_translate(a, b, step)
            r_path = map(list, r.path)
            r.path = it.cycle(r.path)

        logging.info('("Local region", %d): (%s, %s, %s, %d)', k, r, r.style,
                     r_path, k < len(requests))

    # create request objects
    reqs = []
    for r, _, _ in requests:
        name = next(iter(r.symbols))
        reqs.append(Request(r, name, localSpec[name]))
    requests = reqs
    obstacles = [o for o, _, _ in obstacles]

    # set the robot's sensor
    sensingShape = BallBoundary2D([0, 0], robot.diameter*2.5)
    robot.sensor = SimulatedSensor(robot, sensingShape, requests, obstacles)

    logging.info('"Robot sensor constructor": "%s"',
        'SimulatedSensor(robot, BallBoundary2D([0, 0], robot.diameter*2.5),'
        'requests, obstacles)')

    # display workspace
    sim.display()

    # display expanded workspace
    sim.display(expanded=True)

    globalSpec = ('[] ( (<> r1) && (<> r2) && (<> r3) && (<> r4)'
                  + ' && !(o1 || o2 || o3 || o4 ))')
    logging.info('"Global specification": "%s"', globalSpec)


    return robot, sim, globalSpec, localSpec
def caseStudy():
    ############################################################################
    ### Output and debug options ###############################################
    ############################################################################
    outputdir = os.path.abspath('../data_ijrr/example2')
    if not os.path.isdir(outputdir):
        os.makedirs(outputdir)

    # configure logging
    fs = '%(asctime)s [%(levelname)s] -- { %(message)s }'
    dfs = '%m/%d/%Y %I:%M:%S %p'
    loglevel = logging.DEBUG
    logfile = os.path.join(outputdir, 'ijrr_example_2.log')
    verbose = True
    logging.basicConfig(filename=logfile,
                        level=loglevel,
                        format=fs,
                        datefmt=dfs)
    if verbose:
        root = logging.getLogger()
        ch = logging.StreamHandler(sys.stdout)
        ch.setLevel(loglevel)
        ch.setFormatter(logging.Formatter(fs, dfs))
        root.addHandler(ch)

    ############################################################################
    ### Define case study setup (robot parameters, workspace, etc.) ############
    ############################################################################

    # define robot diameter (used to compute the expanded workspace)
    robotDiameter = 0.036

    # define boundary
    nrow, ncol = 5, 6
    cell_size = 0.591
    boundary = BoxBoundary2D([[0, ncol * cell_size], [0, nrow * cell_size]])
    # define boundary style
    boundary.style = {'color': 'black'}
    # create expanded region
    eboundary = BoxBoundary2D(boundary.ranges +
                              np.array([[1, -1], [1, -1]]) * robotDiameter / 2)
    eboundary.style = {'color': 'black'}

    # create robot's workspace and expanded workspace
    wspace = Workspace(boundary=boundary)
    ewspace = Workspace(boundary=eboundary)

    # create robot object
    robot = Cozmo('Cozmo',
                  init=Point2D((1.5 * cell_size, 2.5 * cell_size)),
                  wspace=ewspace,
                  stepsize=0.999)
    robot.diameter = robotDiameter
    robot.localObst = 'local_obstacle'

    logging.info('"Workspace": (%s, %s)', wspace, boundary.style)
    logging.info('"Expanded workspace": (%s, %s)', ewspace, eboundary.style)
    logging.info('"Robot name": "%s"', robot.name)
    logging.info('"Robot initial configuration": %s', robot.initConf)
    logging.info('"Robot step size": %f', robot.controlspace)
    logging.info('"Robot diameter": %f', robot.diameter)
    logging.info(
        '"Robot constructor": "%s"',
        'Cozmo(robot_name, init=initConf, wspace=ewspace, stepsize=stepsize)')
    logging.info('"Local obstacle label": "%s"', robot.localObst)

    # create simulation object
    sim = Simulate2D(wspace, robot, ewspace)
    sim.config['output-dir'] = outputdir
    #     sim.config['background'] = os.path.abspath('../data_ijrr/imMap.png')

    # regions of interest
    R1 = (BoxRegion2D(np.array([[1., 2.], [4., 5.]]) * cell_size,
                      ['r1']), 'brown')
    R2 = (BoxRegion2D(np.array([[4., 5.], [1., 2.]]) * cell_size,
                      ['r2']), 'green')
    R3 = (BoxRegion2D(np.array([[0., 1.], [0., 1.]]) * cell_size,
                      ['r3']), 'red')
    R4 = (BoxRegion2D(np.array([[4., 6.], [4., 5.]]) * cell_size,
                      ['r4']), 'blue')
    # global obstacles
    O1 = (BoxRegion2D(np.array([[1., 2.], [1., 2.]]) * cell_size,
                      ['o1']), 'gray')
    O2 = (BoxRegion2D(np.array([[4., 5.], [2., 3.]]) * cell_size,
                      ['o2']), 'gray')
    O3 = (PolygonRegion2D(
        np.array([[1., 3.], [3., 3.], [3., 5.], [2., 5.], [2., 4.], [1., 4.]])
        * cell_size, ['o3']), 'gray')

    # add all regions
    regions = [R1, R2, R3, R4, O1, O2, O3]

    # add regions to workspace
    for k, (r, c) in enumerate(regions):
        # add styles to region
        addStyle(r, style={'facecolor': c})
        # add region to workspace
        sim.workspace.addRegion(r)
        # create expanded region
        er = expandRegion(r, robot.diameter / 2)
        # add style to the expanded region
        addStyle(er, style={'facecolor': c})
        # add expanded region to the expanded workspace
        sim.expandedWorkspace.addRegion(er)

        logging.info('("Global region", %d): (%s, %s)', k, r, r.style)

    # local  requests
    F1 = (BallRegion2D([3.24, 1.98], 0.3, ['fire']), ('orange', 0.3))
    F2 = (BallRegion2D([1.26, 0.48], 0.3, ['fire']), ('orange', 0.3))
    S2 = (BallRegion2D([4.32, 1.48], 0.3, ['survivor']), ('yellow', 0.3))
    requests = [F1, F2, S2]
    # define local specification as a priority function
    localSpec = {'survivor': 0, 'fire': 1}
    logging.info('"Local specification": %s', localSpec)
    localSpec_cube_color = {'survivor': 3, 'fire': 2}
    # local obstacles
    obstacles = []

    # add style to local requests and obstacles
    for k, (r, c) in enumerate(requests + obstacles):
        # add styles to region
        addStyle(r, style={'facecolor': to_rgba(*c)})  #FIMXE: HACK
        r.cube_color = localSpec_cube_color[next(iter(r.symbols))]

        logging.info('("Local region", %d): (%s, %s, %s, %d)', k, r, r.style,
                     None, k < len(requests))

    # create request objects
    reqs = []
    for r, _ in requests:
        name = next(iter(r.symbols))
        reqs.append(Request(r, name, localSpec[name]))
    requests = reqs
    obstacles = [o for o, _, _ in obstacles]

    # set the robot's sensor
    sensingShape = BallBoundary2D([0, 0], 1.0)
    robot.sensor = CozmoSensor(robot, sensingShape, requests, obstacles)
    robot.sensor.reset()

    logging.info(
        '"Robot sensor constructor": "%s"',
        'CozmoSensor(robot, BallBoundary2D([0, 0], 0.5), requests, obstacles)')

    # display workspace
    sim.display()

    # display expanded workspace
    sim.display(expanded=True)

    ############################################################################
    ### Generate global transition system and off-line control policy ##########
    ############################################################################

    globalSpec = ('[] ( (<> r1) && (<> r2) && (<> r3) && (<> r4)'
                  ' && !(o1 || o2 || o3))')
    logging.info('"Global specification": "%s"', globalSpec)

    # initialize incremental product automaton
    checker = IncrementalProduct(
        globalSpec)  #, specFile='ijrr_globalSpec.txt')
    logging.info('"Buchi size": (%d, %d)', checker.buchi.g.number_of_nodes(),
                 checker.buchi.g.number_of_edges())

    # initialize global off-line RRG planner
    sim.offline = RRGPlanner(robot, checker, iterations=1000)
    sim.offline.eta = [0.5, 1.0]  # good bounds for the planar case study

    logging.info('"Start global planning": True')
    with Timer(op_name='global planning', template='"%s runtime": %f'):
        found = sim.offline.solve()
        logging.info('"Found solution": %s', found)
        if not found:
            return

    logging.info('"Iterations": %d', sim.offline.iteration)
    logging.info('"Size of TS": %s', sim.offline.ts.size())
    logging.info('"Size of PA": %s', sim.offline.checker.size())

    # save global transition system and control policy
    sim.offline.ts.save(os.path.join(outputdir, 'ts.yaml'))

    ############################################################################
    ### Display the global transition system and the off-line control policy ###
    ############################################################################

    # display workspace and global transition system
    prefix, suffix = sim.offline.checker.globalPolicy(sim.offline.ts)
    sim.display(expanded=False, solution=prefix)
    sim.display(expanded=False, solution=suffix)
    sim.display(expanded=False, solution=prefix + suffix[1:])
    logging.info('"global policy": (%s, %s)', prefix, suffix)
    logging.info('"End global planning": True')

    # move to start position
    logging.debug('Moving to start configuration: %s', robot.initConf)
    sim.robot.move([robot.initConf])

    ############################################################################
    ### Execute on-line path planning algorithm ################################
    ############################################################################

    # compute potential for each state of PA
    with Timer(op_name='Computing potential function',
               template='"%s runtime": %f'):
        if not compute_potentials(sim.offline.checker):
            return

    # set the step size for the local controller controlspace
    robot.controlspace = 0.20

    # initialize local on-line RRT planner
    sim.online = LocalPlanner(sim.offline.checker,
                              sim.offline.ts,
                              robot,
                              localSpec,
                              eta=robot.controlspace)
    sim.online.detailed_logging = True

    # define number of surveillance cycles to run
    cycles = 2
    # execute controller
    cycle = -1  # number of completed cycles, -1 accounts for the prefix
    while cycle < cycles:
        # update the locally sensed requests and obstacles
        requests, obstacles = robot.sensor.sense()
        # TODO: sense robot location
        # TODO: update index in local plan
        # TODO: add logging marker for start time for planning
        logging.info('"plan start time": %f', time.time())
        with Timer(op_name='local planning', template='"%s runtime": %f'):
            # feed data to planner and get next control input
            nextConf = sim.online.execute(requests, obstacles)
        # TODO: add logging marker for stop time for planning
        logging.info('"plan stop time": %f', time.time())

        #         sim.display(expanded=True, localinfo=('plan', 'trajectory'))

        # enforce movement along plan
        # FIXME: should pass only plan
        robot.move([nextConf])  # + sim.online.local_plan)
        # if completed cycle increment cycle
        if sim.update():
            cycle += 1

    logging.info('"Local online planning finished": True')