def __init__(self, km,
                       actuated_pose,
                       goal_pose,
                       controlled_symbols,
                       weight_override=None,
                       draw_fn=None):
        
        eef = actuated_pose
        goal_pos_error = gm.norm(gm.pos_of(eef) - gm.pos_of(goal_pose))
        self.eef_rot = eef[:3, :3]
        self.goal_rot = goal_pose[:3, :3]
        self.rot_error_matrix = self.eef_rot - self.goal_rot
        goal_rot_error = gm.norm(self.rot_error_matrix)

        rot_align_scale = gm.exp(-3 * goal_rot_error) 

        goal_constraints = {'align position': SC(-goal_pos_error * rot_align_scale,
                                                 -goal_pos_error * rot_align_scale, 10, goal_pos_error),
                            'align rotation': SC(-goal_rot_error, -goal_rot_error, 1, goal_rot_error)}

        self.goal_rot_error = goal_rot_error

        constraints = km.get_constraints_by_symbols(gm.free_symbols(eef).union(controlled_symbols))
        cvs, constraints = generate_controlled_values(constraints, controlled_symbols, weights=weight_override)
        cvs = depth_weight_controlled_values(km, cvs, exp_factor=1.02)

        self.draw_fn = draw_fn

        self.qp = TQPB(constraints,
                       goal_constraints,
                       cvs)
Example #2
0
    def _build_ext_symbol_map(self, km, ext_paths):
        # total_ext_symbols = set()
        # Map of path to set of symbols
        self._target_body_map = {}
        self._grasp_poses = {}
        self._var_upper_bound = {}

        for path, grasp_pose in ext_paths.items():
            data = km.get_data(path)
            if not isinstance(data, Frame):
                print(f'Given external path "{path}" is not a frame.')
                continue
            self._grasp_poses[path] = gm.dot(data.pose, grasp_pose)

            symbols = {
                s
                for s in gm.free_symbols(data.pose) if 'location' not in str(s)
            }

            static_bounded_vars, \
            static_bounds, \
            _ = static_var_bounds(km, symbols)

            print(static_bounds.shape)
            if len(static_bounds) == 0:
                constraints = km.get_constraints_by_symbols(symbols)
                raise Exception(
                    'None of {} seem to have static bounds. Constraints are:\n  '
                    .format(
                        ', '.join(str(s) for s in symbols),
                        '\n  '.join(f'{n} : {c}'
                                    for n, c in constraints.items())))

            self._var_upper_bound.update(
                zip(static_bounded_vars, static_bounds[:, 1]))

            # total_ext_symbols.update(gm.free_symbols(data.pose))
            self._target_body_map[path] = set(static_bounded_vars)

        list_sets = list(self._target_body_map.values())
        for x, s in enumerate(list_sets):
            # Only keep symbols unique to one target
            s.difference_update(list_sets[:x] + list_sets[x + 1:])

        for p, symbols in self._target_body_map.items():
            for s in symbols:
                self._target_map[s] = p

        print('Monitored symbols are:\n  {}'.format('\n  '.join(
            str(s) for s in self._target_map.keys())))
Example #3
0
    def __init__(self, km, controlled_symbols, resting_pose, camera_path=None):
        tucking_constraints = {}
        if resting_pose is not None:
            tucking_constraints = {
                f'tuck {s}': SC(p - s, p - s, 1, s)
                for s, p in resting_pose.items()
            }
            # print('Tuck state:\n  {}\nTucking constraints:\n  {}'.format('\n  '.join(['{}: {}'.format(k, v) for k, v in self._resting_pose.items()]), '\n  '.join(tucking_constraints.keys())))

        # tucking_constraints.update(self.taxi_constraints)

        self.use_camera = camera_path is not None
        if camera_path is not None:
            self._poi_pos = gm.Symbol('poi')
            poi = gm.point3(1.5, 0.5, 0.0) + gm.vector3(
                0, self._poi_pos * 2.0, 0)

            camera = km.get_data(camera_path)
            cam_to_poi = poi - gm.pos_of(camera.pose)
            lookat_dot = 1 - gm.dot_product(gm.x_of(camera.pose),
                                            cam_to_poi) / gm.norm(cam_to_poi)
            tucking_constraints['sweeping gaze'] = SC(-lookat_dot * 5,
                                                      -lookat_dot * 5, 1,
                                                      lookat_dot)

        symbols = set()
        for c in tucking_constraints.values():
            symbols |= gm.free_symbols(c.expr)

        joint_symbols = {
            s
            for s in symbols if gm.get_symbol_type(s) != gm.TYPE_UNKNOWN
        }
        controlled_symbols = {gm.DiffSymbol(s) for s in joint_symbols}

        hard_constraints = km.get_constraints_by_symbols(
            symbols.union(controlled_symbols))

        controlled_values, hard_constraints = generate_controlled_values(
            hard_constraints, controlled_symbols)
        controlled_values = depth_weight_controlled_values(
            km, controlled_values)

        self.qp = TQPB(hard_constraints, tucking_constraints,
                       controlled_values)
        self._start = Time.now()
Example #4
0
    def _build_ext_symbol_map(self, km, ext_paths):
        # total_ext_symbols = set()
        # Map of path to set of symbols
        self._target_body_map = {}

        for path in ext_paths:
            data = km.get_data(path)
            if not isinstance(data, RigidBody):
                print(f'Given external path "{path}" is not a rigid body.')
                continue

            # total_ext_symbols.update(gm.free_symbols(data.pose))
            self._target_body_map[path] = {s for s in gm.free_symbols(data.pose) if 'location' not in str(s)}

        list_sets = list(self._target_body_map.values())
        for x, s in enumerate(list_sets):
            # Only keep symbols unique to one target
            s.difference_update(list_sets[:x] + list_sets[x + 1:])

        for p, symbols in self._target_body_map.items():
            for s in symbols:
                self._target_map[s] = p
    def __init__(self,
                 observations,
                 constraints,
                 Q=None,
                 transition_rules=None,
                 trim_threshold=None):
        """Sets up an EKF estimating the underlying state of a set of observations.
        
        Args:
            observations (dict): A dict of observations. Names are mapped to 
                                 any kind of symbolic expression/matrix
            constraints (dict): A dict of named constraints that govern the 
                                configuration space of the estimated quantities
            Q (matrix, optional): Process noise of the estimated quantities. 
                                  Note: Quantities are expected to be ordered alphabetically
            transition_rules (dict, optional): Maps symbols to their transition rule.
                                               Rules will be generated automatically, if not provided here.
        """
        state_vars = union([gm.free_symbols(o) for o in observations.values()])

        self.ordered_vars = [
            s for _, s in sorted((str(s), s) for s in state_vars)
        ]
        self.Q = Q if Q is not None else np.zeros(
            (len(self.ordered_vars), len(self.ordered_vars)))

        st_fn = {}
        for s in self.ordered_vars:
            st_fn[s] = gm.wrap_expr(s + gm.DiffSymbol(s) * EKFModel.DT_SYM)

        if transition_rules is not None:
            varset = set(self.ordered_vars).union(
                {gm.DiffSymbol(s)
                 for s in self.ordered_vars}).union({EKFModel.DT_SYM})
            for s, r in transition_rules.items():
                if s in st_fn:
                    if len(gm.free_symbols(r).difference(varset)) == 0:
                        st_fn[s] = gm.wrap_expr(r)
                    else:
                        print(
                            f'Dropping rule "{s}: {r}". Symbols missing from state: {gm.free_symbols(r).difference(varset)}'
                        )
        control_vars = union([gm.free_symbols(r) for r in st_fn.values()]) \
                        .difference(self.ordered_vars)            \
                        .difference({EKFModel.DT_SYM})
        self.ordered_controls = [
            s for _, s in sorted((str(s), s) for s in control_vars)
        ]

        # State as column vector n * 1
        temp_g_fn = gm.Matrix(
            [gm.extract_expr(st_fn[s]) for s in self.ordered_vars])
        self.g_fn = gm.speed_up(temp_g_fn, [EKFModel.DT_SYM] +
                                self.ordered_vars + self.ordered_controls)
        temp_g_prime_fn = gm.Matrix([[
            gm.extract_expr(st_fn[s][d]) if d in st_fn[s] else 0
            for d in self.ordered_controls
        ] for s in self.ordered_vars])
        self.g_prime_fn = gm.speed_up(temp_g_prime_fn,
                                      [EKFModel.DT_SYM] + self.ordered_vars +
                                      self.ordered_controls)

        self.obs_labels = []
        self.takers = []
        flat_obs = []
        for o_label, o in sorted(observations.items()):
            if gm.is_symbolic(o):
                if gm.is_matrix(o):
                    if type(o) == gm.GM:
                        components = zip(
                            sum([[(y, x) for x in range(o.shape[1])]
                                 for y in range(o.shape[0])], []), iter(o))
                    else:
                        components = zip(
                            sum([[(y, x) for x in range(o.shape[1])]
                                 for y in range(o.shape[0])], []),
                            o.T.elements())  # Casadi iterates vertically
                    indices = []
                    for coords, c in components:
                        if gm.is_symbolic(c):
                            self.obs_labels.append('{}_{}_{}'.format(
                                o_label, *coords))
                            flat_obs.append(gm.wrap_expr(c))
                            indices.append(coords[0] * o.shape[1] + coords[1])
                    if len(indices) > 0:
                        self.takers.append((o_label, indices))
                else:
                    self.obs_labels.append(o_label)
                    flat_obs.append(gm.wrap_expr(o))
                    self.takers.append((o_label, [0]))

        temp_h_fn = gm.Matrix([gm.extract_expr(o) for o in flat_obs])
        self.h_fn = gm.speed_up(temp_h_fn, self.ordered_vars)
        temp_h_prime_fn = gm.Matrix([[
            gm.extract_expr(o[d]) if d in o else 0
            for d in self.ordered_controls
        ] for o in flat_obs])
        self.h_prime_fn = gm.speed_up(temp_h_prime_fn, self.ordered_vars)

        state_constraints = {}
        for n, c in constraints.items():
            if gm.is_symbol(c.expr):
                s = gm.free_symbols(c.expr).pop()
                fs = gm.free_symbols(c.lower).union(gm.free_symbols(c.upper))
                if len(fs.difference({s})) == 0:
                    state_constraints[s] = (float(gm.subs(c.lower, {s: 0})),
                                            float(gm.subs(c.upper, {s: 0})))

        self.state_bounds = np.array([
            state_constraints[s]
            if s in state_constraints else [-np.pi, np.pi]
            for s in self.ordered_vars
        ])
        self.R = None  # np.zeros((len(self.obs_labels), len(self.obs_labels)))
        self.trim_threshold = trim_threshold
                      'shoulder_pan_joint' : 0.3,
                      'elbow_flex_joint'   : 1.72,
                      'forearm_roll_joint' : -1.2,
                      'upperarm_roll_joint': -1.57,
                      'wrist_flex_joint'   : 1.66,
                      'shoulder_lift_joint': 1.4,
                      'torso_lift_joint'   : 0.2}
        start_pose = {gm.Position(Path(f'{robot_path}/{n}')): v for n, v in start_pose.items()}
    else:
        joint_symbols, \
        robot_controlled_symbols, \
        start_pose, \
        eef, \
        blacklist = generic_setup(km, robot_path, rospy.get_param('~eef', 'gripper_link'))

    collision_world = km.get_active_geometry(gm.free_symbols(handle.pose).union(gm.free_symbols(eef.pose)))

    # Init step
    grasp_in_handle = gm.dot(gm.translation3(0.04, 0, 0), gm.rotation3_rpy(math.pi * 0.5, 0, math.pi))
    goal_pose       = gm.dot(handle.pose, grasp_in_handle)
    goal_0_pose     = gm.subs(goal_pose, {s: 0 for s in gm.free_symbols(goal_pose)})

    start_state = {s: 0 for s in gm.free_symbols(collision_world)}
    start_state.update(start_pose)
    ik_err, robot_start_state = ik_solve_one_shot(km, eef.pose, start_state, goal_0_pose)

    start_state.update({s: 0 for s in gm.free_symbols(handle.pose)})
    start_state.update(robot_start_state)

    collision_world.update_world(start_state)
    def __init__(self,
                 km,
                 lead_goal_constraints,
                 follower_goal_constraints,
                 t_leader=TQPB,
                 t_follower=TQPB,
                 f_gen_lead_cvs=None,
                 f_gen_follower_cvs=None,
                 visualizer=None,
                 controls_blacklist=set(),
                 transition_overrides=None):
        lead_symbols = union(
            gm.free_symbols(c.expr) for c in lead_goal_constraints.values())
        follower_symbols = union(
            gm.free_symbols(c.expr)
            for c in follower_goal_constraints.values())
        self.lead_symbols = lead_symbols
        self.follower_symbols = follower_symbols

        self.lead_controlled_symbols = {
            s
            for s in union(
                gm.get_diff_symbols(c.expr)
                for c in lead_goal_constraints.values())
            if s not in controls_blacklist
        }
        # Only update the symbols that are unique to the follower
        self.follower_controlled_symbols = {
            s
            for s in union(
                gm.get_diff_symbols(c.expr)
                for c in follower_goal_constraints.values()) if
            s not in controls_blacklist and gm.IntSymbol(s) not in lead_symbols
        }

        f_gen_lead_cvs = self.gen_controlled_values if f_gen_lead_cvs is None else f_gen_lead_cvs
        lead_cvs, \
        lead_constraints = f_gen_lead_cvs(km,
                                          km.get_constraints_by_symbols(self.lead_controlled_symbols.union({gm.IntSymbol(s) for s in self.lead_controlled_symbols})),
                                          self.lead_controlled_symbols)

        f_gen_follower_cvs = self.gen_controlled_values if f_gen_follower_cvs is None else f_gen_follower_cvs
        follower_cvs, \
        follower_constraints = f_gen_follower_cvs(km,
                                                  km.get_constraints_by_symbols(self.follower_controlled_symbols.union({gm.IntSymbol(s) for s in self.follower_controlled_symbols})),
                                                  self.follower_controlled_symbols)

        if issubclass(t_leader, GQPB):
            lead_world = km.get_active_geometry(lead_symbols)
            self.lead_qp = t_leader(lead_world,
                                    lead_constraints,
                                    lead_goal_constraints,
                                    lead_cvs,
                                    visualizer=visualizer)
        else:
            self.lead_qp = t_leader(lead_constraints, lead_goal_constraints,
                                    lead_cvs)

        self.sym_dt = gm.Symbol('dT')
        self.lead_o_symbols, \
        self.lead_t_function, \
        self.lead_o_controls = generate_transition_function(self.sym_dt, lead_symbols, transition_overrides)

        self.follower_o_symbols, \
        self.follower_t_function, \
        self.follower_o_controls = generate_transition_function(self.sym_dt,
                                                                {gm.IntSymbol(s) for s in self.follower_controlled_symbols},
                                                                transition_overrides)

        self.follower_o_bounds = list(self.follower_controlled_symbols)
        follower_ctrl_bounds = [
            sum([[c.lower, c.upper]
                 for c in km.get_constraints_by_symbols({s}).values()], [])
            for s in self.follower_o_bounds
        ]

        max_bounds = max(len(row) for row in follower_ctrl_bounds)

        for s, row in zip(self.follower_o_bounds, follower_ctrl_bounds):
            row.extend([1e3] * (max_bounds - len(row)))
            print(f'{s}: {row}')

        follower_ctrl_bounds = gm.Matrix(follower_ctrl_bounds).T
        self.follower_ctrl_bounds_params = list(
            gm.free_symbols(follower_ctrl_bounds))
        self.follower_ctrl_bounds_f = gm.speed_up(
            follower_ctrl_bounds, self.follower_ctrl_bounds_params)

        self.follower_delta_map = {
            gm.IntSymbol(s): s
            for s in self.follower_controlled_symbols
        }

        if issubclass(t_follower, GQPB):
            follower_world = km.get_active_geometry(follower_symbols)
            self.follower_qp = t_follower(follower_world,
                                          follower_constraints,
                                          follower_goal_constraints,
                                          follower_cvs,
                                          visualizer=visualizer)
        else:
            self.follower_qp = t_follower(follower_constraints,
                                          follower_goal_constraints,
                                          follower_cvs)
Example #8
0
    def behavior_update(self):
        state_count = 0

        while not rospy.is_shutdown() and not self._kys:
            loop_start = rospy.Time.now()

            with self._state_lock:
                if self._robot_state_update_count <= state_count:
                    rospy.sleep(0.01)
                    continue
                state_count = self._robot_state_update_count

            if self.controller is not None:
                now = rospy.Time.now()
                with self._state_lock:
                    deltaT = 0.05 if self._last_controller_update is None else (
                        now - self._last_controller_update).to_sec()
                    try:
                        command = self.controller.get_cmd(self._state,
                                                          deltaT=deltaT)
                    except Exception as e:
                        print(traceback.format_exc())
                        rospy.signal_shutdown('die lol')

                self.robot_command_processor.send_command(command)
                self._last_controller_update = now

            # Lets not confuse the tracker
            if self._phase != 'opening' and self._last_external_cmd_msg is not None:
                # Ensure that velocities are assumed to be 0 when not operating anything
                self._last_external_cmd_msg.value = [0] * len(
                    self._last_external_cmd_msg.value)
                self.pub_external_command.publish(self._last_external_cmd_msg)
                self._last_external_cmd_msg = None

            if self._phase == 'idle':
                # if there is no controller, instantiate idle

                # check for new target
                # -> open gripper
                #    instantiate 6d controller
                #    switch to "grasping"
                if self.controller is None:
                    self.gripper_wrapper.sync_set_gripper_position(0.07)
                    self.controller = self._idle_controller

                with self._state_lock:
                    for s, p in self._target_map.items():
                        if s in self._state and self._state[
                                s] < self._var_upper_bound[
                                    s] * self.monitoring_threshold:  # Some thing in the scene is closed
                            self._current_target = p
                            print(f'New target is {self._current_target}')
                            self.gripper_wrapper.sync_set_gripper_position(
                                0.07)
                            self._last_controller_update = None
                            print('Gripper is open. Proceeding to grasp...')
                            draw_fn = None

                            eef_pose = self.km.get_data(self.eef_path).pose

                            if self.visualizer is not None:
                                self.visualizer.begin_draw_cycle('grasp pose')
                                self.visualizer.draw_poses(
                                    'grasp pose', np.eye(4), 0.2, 0.01, [
                                        gm.subs(self._grasp_poses[p],
                                                self._state)
                                    ])
                                self.visualizer.render('grasp pose')

                                def draw_fn(state):
                                    self.visualizer.begin_draw_cycle(
                                        'debug_grasp')
                                    self.visualizer.draw_poses(
                                        'debug_grasp', np.eye(4), 1.0, 0.01, [
                                            gm.subs(eef_pose, state),
                                            gm.subs(self._grasp_poses[p],
                                                    state)
                                        ])
                                    self.visualizer.render('debug_grasp')
                                    # print('\n'.join(f'{s}: {v}' for s, v in state.items()))

                            self.controller = SixDPoseController(
                                self.km, eef_pose, self._grasp_poses[p],
                                self.controlled_symbols, self.weights, draw_fn)

                            self._phase = 'grasping'
                            print(f'Now entering {self._phase} state')
                            break
                    else:
                        print(
                            'None of the monitored symbols are closed:\n  {}'.
                            format('\n  '.join(
                                f'{self._state[s]} < {self._var_upper_bound[s]}'
                                for s in self._target_map.keys()
                                if s in self._state)))
            elif self._phase == 'grasping':
                # check if grasp is acheived
                # -> close gripper
                #    instantiate cascading controller
                #    switch to "opening"
                # if there is no more command but the goal error is too great -> "homing"
                if self.controller.equilibrium_reached(0.03, -0.03):
                    if self.controller.current_error() > 0.01:
                        self.controller = self._idle_controller
                        self._phase = 'homing'
                        print(f'Now entering {self._phase} state')
                    else:
                        print('Closing gripper...')
                        self.gripper_wrapper.sync_set_gripper_position(0, 80)
                        print('Generating opening controller')

                        eef = self.km.get_data(self.eef_path)
                        obj = self.km.get_data(self._current_target)
                        with self._state_lock:
                            static_eef_pose = gm.subs(eef.pose, self._state)
                            static_object_pose = gm.subs(obj.pose, self._state)

                        offset_pose = np_inverse_frame(static_object_pose).dot(
                            static_eef_pose)
                        print(offset_pose)

                        goal_pose = gm.dot(obj.pose, gm.Matrix(offset_pose))

                        goal_pos_error = gm.norm(
                            gm.pos_of(eef.pose) - gm.pos_of(goal_pose))
                        goal_rot_error = gm.norm(eef.pose[:3, :3] -
                                                 goal_pose[:3, :3])

                        target_symbols = self._target_body_map[
                            self._current_target]
                        lead_goal_constraints = {
                            f'open_{s}': SC(self._var_upper_bound[s] - s, 1000,
                                            1, s)
                            for s in target_symbols
                            if s in self._var_upper_bound
                        }
                        for n, c in lead_goal_constraints.items():
                            print(f'{n}: {c}')

                        follower_goal_constraints = {
                            'keep position':
                            SC(-goal_pos_error, -goal_pos_error, 10,
                               goal_pos_error),
                            'keep rotation':
                            SC(-goal_rot_error, -goal_rot_error, 1,
                               goal_rot_error)
                        }

                        blacklist = {
                            gm.Velocity(Path('pr2/torso_lift_joint'))
                        }.union({
                            gm.DiffSymbol(s)
                            for s in gm.free_symbols(obj.pose)
                            if 'location' in str(s)
                        })
                        # blacklist = {gm.DiffSymbol(s) for s in gm.free_symbols(obj.pose) if 'location' in str(s)}

                        self.controller = CascadingQP(
                            self.km,
                            lead_goal_constraints,
                            follower_goal_constraints,
                            f_gen_follower_cvs=gen_dv_cvs,
                            controls_blacklist=blacklist,
                            t_follower=GQPB,
                            visualizer=None  # self.visualizer
                        )
                        print(self.controller)

                        # def debug_draw(vis, state, cmd):
                        #     vis.begin_draw_cycle('lol')
                        #     vis.draw_poses('lol', np.eye(4), 0.2, 0.01,
                        #                    [gm.subs(goal_pose, state),
                        #                     gm.subs(eef.pose, state)])
                        #     vis.render('lol')

                        # self.controller.follower_qp._cb_draw = debug_draw

                        # self.gripper_wrapper.sync_set_gripper_position(0.07)
                        # rospy.signal_shutdown('die lol')
                        # return
                        self._last_controller_update = None
                        self._phase = 'opening'
                        print(f'Now entering {self._phase} state')
            elif self._phase == 'opening':
                # Wait for monitored symbols to be in open position
                # -> open gripper
                #    generate 6d retraction goal: -10cm in tool frame
                #    spawn 6d controller
                #    switch to "retracting"

                # self.visualizer.begin_draw_cycle('world state')
                # with self._state_lock:
                #     self._world.update_world(self._state)
                # self.visualizer.draw_world('world state', self._world, b=0)
                # self.visualizer.render('world state')

                external_command = {
                    s: v
                    for s, v in command.items()
                    if s not in self.controlled_symbols
                }
                ext_msg = ValueMapMsg()
                ext_msg.header.stamp = now
                ext_msg.symbol, ext_msg.value = zip(
                    *[(str(s), v) for s, v in external_command.items()])
                self.pub_external_command.publish(ext_msg)
                self._last_external_cmd_msg = ext_msg

                with self._state_lock:
                    current_external_error = {
                        s: self._state[s]
                        for s in self._target_body_map[self._current_target]
                    }
                print('Current error state:\n  {}'.format('\n  '.join(
                    [f'{s}: {v}' for s, v in current_external_error.items()])))

                gripper_err = self.gripper_wrapper.get_latest_error()
                # if gripper_err < 0.0005: # Grasped object is thinner than 5mm aka we lost it
                #     self.controller = self._idle_controller
                #     self._phase = 'homing'
                #     print(f'Grasped object seems to have slipped ({gripper_err}). Returning to home...')
                #     return

                if min([
                        v >=
                        self._var_upper_bound[s] * self.acceptance_threshold
                        for s, v in current_external_error.items()
                ]):
                    print('Target fulfilled. Setting it to None')
                    self._current_target = None

                    eef = self.km.get_data(self.eef_path)
                    with self._state_lock:
                        static_eef_pose = gm.subs(eef.pose, self._state)
                    goal_pose = static_eef_pose.dot(
                        np.array([[1, 0, 0, -0.12], [0, 1, 0, 0], [0, 0, 1, 0],
                                  [0, 0, 0, 1]]))

                    self.controller = SixDPoseController(
                        self.km, eef.pose, goal_pose, self.controlled_symbols,
                        self.weights)

                    self.gripper_wrapper.sync_set_gripper_position(0.07)
                    self._last_controller_update = None
                    self._phase = 'retracting'
                    print(f'Now entering {self._phase} state')
                else:
                    remainder = (1 / 3) - (rospy.Time.now() -
                                           loop_start).to_sec()
                    if remainder > 0:
                        rospy.sleep(remainder)

            elif self._phase == 'retracting':
                # Wait for retraction to complete (Currently just skipping)
                # -> spawn idle controller
                #    switch to "homing"
                if self.controller.equilibrium_reached(0.035, -0.035):
                    self.controller = self._idle_controller
                    self._phase = 'homing'
                    print(f'Now entering {self._phase} state')
            elif self._phase == 'homing':
                # Wait for idle controller to have somewhat low error
                # -> switch to "idle"
                if self.controller is None:
                    self.gripper_wrapper.sync_set_gripper_position(0.07)
                    self.controller = self._idle_controller
                    continue

                if self.controller.equilibrium_reached(0.1, -0.1):
                    self._phase = 'idle'
                    print(f'Now entering {self._phase} state')
            else:
                raise Exception(f'Unknown state "{self._phase}')
Example #9
0
    def __init__(self,
                 km,
                 robot_command_processor,
                 gripper_wrapper,
                 robot_prefix,
                 eef_path,
                 ext_paths_and_poses,
                 controlled_symbols,
                 cam_path=None,
                 weights=None,
                 resting_pose=None,
                 visualizer=None,
                 monitoring_threshold=0.7,
                 acceptance_threshold=0.8,
                 control_mode='vel'):
        self.km = km
        self.robot_command_processor = robot_command_processor
        self.gripper_wrapper = gripper_wrapper
        self.control_mode = control_mode
        self.robot_prefix = robot_prefix
        self.eef_path = eef_path
        self.cam_path = cam_path

        self.visualizer = visualizer
        if weights is None:
            cvs, _ = gen_dv_cvs(km, {}, controlled_symbols)
            self.weights = {c.symbol: c.weight_id for c in cvs.values()}
        else:
            self.weights = weights

        self.controlled_symbols = controlled_symbols

        self.controller = None

        self.monitoring_threshold = monitoring_threshold
        self.acceptance_threshold = acceptance_threshold

        self._phase = 'homing'

        self._state_lock = RLock()
        self._state = {}
        self._robot_state_update_count = 0
        self._target_map = {}
        self._target_body_map = {}
        self._last_controller_update = None

        self._current_target = None
        self._last_external_cmd_msg = None

        self._idle_controller = IdleController(km, self.controlled_symbols,
                                               resting_pose, None)

        self._build_ext_symbol_map(km, ext_paths_and_poses)

        self._world = km.get_active_geometry(
            gm.free_symbols(km.get_data(self.eef_path).pose).union(
                self._target_map.keys()))

        self.pub_external_command = rospy.Publisher('~external_command',
                                                    ValueMapMsg,
                                                    queue_size=1,
                                                    tcp_nodelay=True)

        self.sub_external_js = rospy.Subscriber('~external_js',
                                                ValueMapMsg,
                                                callback=self.cb_external_js,
                                                queue_size=1)
        self.robot_command_processor.register_state_cb(self.cb_robot_js)

        self._kys = False
        self._behavior_thread = threading.Thread(target=self.behavior_update)
        self._behavior_thread.start()
Example #10
0
def generate_push_closing(km,
                          grounding_state,
                          controlled_symbols,
                          eef_pose,
                          obj_pose,
                          eef_path,
                          obj_path,
                          nav_method='cross',
                          cp_offset=0,
                          static_symbols=set()):
    # CONTACT GEOMETRY
    robot_cp, object_cp, contact_normal = contact_geometry(
        eef_pose, obj_pose, eef_path, obj_path)
    object_cp = object_cp - contact_normal * cp_offset
    geom_distance = gm.dot_product(contact_normal, robot_cp - object_cp)
    coll_world = km.get_active_geometry(gm.free_symbols(geom_distance))

    # GEOMETRY NAVIGATION LOGIC
    # This is exploiting task knowledge which makes this function inflexible.
    contact_grad = sum([
        sign(-grounding_state[s]) *
        gm.vector3(gm.diff(object_cp[0], s), gm.diff(object_cp[1], s),
                   gm.diff(object_cp[2], s))
        for s in gm.free_symbols(obj_pose) if s not in static_symbols
    ], gm.vector3(0, 0, 0))
    neutral_tangent = gm.cross(contact_grad, contact_normal)
    active_tangent = gm.cross(neutral_tangent, contact_normal)

    contact_constraints, in_contact = generate_contact_model(
        robot_cp, controlled_symbols, object_cp, contact_normal,
        gm.free_symbols(obj_pose))

    target_pos = None
    if nav_method == 'linear':
        geom_distance = gm.norm(object_cp + active_tangent * geom_distance +
                                contact_grad * 0.05 - robot_cp)
    elif nav_method == 'cubic':
        dist_scaling = 2**(-0.5 * ((geom_distance - 0.2) / (0.2 * 0.2))**2)
        geom_distance = gm.norm(object_cp + active_tangent * dist_scaling -
                                robot_cp)
    elif nav_method == 'cross':
        geom_distance = gm.norm(object_cp +
                                active_tangent * gm.norm(neutral_tangent) +
                                contact_grad * 0.05 - robot_cp)
    elif nav_method == 'cross_deep':
        geom_distance = gm.norm(object_cp +
                                active_tangent * gm.norm(neutral_tangent) +
                                contact_grad *
                                -gm.dot_product(contact_normal, contact_grad) -
                                robot_cp)
    elif nav_method == 'none' or nav_method is None:
        pass
    elif nav_method == 'proj':
        obj_cp_dist = gm.dot_product(contact_normal,
                                     object_cp - gm.pos_of(obj_pose))
        target_pos = gm.pos_of(
            obj_pose
        ) + contact_normal * obj_cp_dist - contact_normal * 0.02  # Drive into the surface
        geom_distance = gm.norm(robot_cp - target_pos)

    contact_relative_pos = gm.dot(gm.rot_of(obj_pose),
                                  robot_cp - gm.pos_of(obj_pose))
    contact_relative_vel = gm.vector3(
        sum([gm.diff(contact_relative_pos[0], s) for s in controlled_symbols],
            0),
        sum([gm.diff(contact_relative_pos[1], s) for s in controlled_symbols],
            0),
        sum([gm.diff(contact_relative_pos[2], s) for s in controlled_symbols],
            0))

    # PUSH CONSTRAINT GENERATION
    constraints = km.get_constraints_by_symbols(
        gm.free_symbols(geom_distance).union(controlled_symbols))
    constraints.update(contact_constraints)

    # for x, n in enumerate('xyz'):
    #     constraints[f'zero tangent vel_{n}'] = Constraint((1 -  in_contact) * -1e3,
    #                                                       (1 -  in_contact) *  1e3, contact_relative_pos[x] * (1.0 + 0.1 * x))

    def debug_draw(vis, state, cmd):
        vis.begin_draw_cycle('debug_vecs')
        s_object_cp = gm.subs(object_cp, state)
        s_neutral_tangent = gm.subs(neutral_tangent, state)
        vis.draw_vector('debug_vecs',
                        s_object_cp,
                        gm.subs(contact_grad, state),
                        r=0,
                        b=0)
        vis.draw_vector('debug_vecs',
                        s_object_cp,
                        gm.subs(active_tangent, state),
                        r=0,
                        b=1)
        vis.draw_vector('debug_vecs',
                        s_object_cp,
                        gm.subs(neutral_tangent, state),
                        r=1,
                        g=1,
                        b=0)
        if target_pos is not None:
            vis.draw_sphere('debug_vecs',
                            gm.subs(target_pos, state),
                            0.01,
                            r=0,
                            b=1)
        # print(f'{gm.norm(gm.subs(contact_normal, state))}')
        # vis.draw_vector('debug_vecs', s_object_cp, s_ortho_vel_vec, r=1, b=0)
        vis.render('debug_vecs')

    return constraints, geom_distance, coll_world, PushingInternals(
        robot_cp, contact_normal, contact_relative_pos, contact_relative_vel,
        debug_draw)
angle_hinge = gm.Symbol('angle_top')
x_hinge_in_parent, z_hinge_in_parent = [
    gm.Symbol(f'hinge_in_parent_{x}') for x in 'xz'
]
x_child_in_hinge, z_child_in_hinge = [
    gm.Symbol(f'child_in_hinge_{x}') for x in 'xz'
]

fwd_kinematic_hinge = gm.dot(
    gm.translation3(x_hinge_in_parent, 0, z_hinge_in_parent),
    gm.rotation3_axis_angle(gm.vector3(0, -1, 0), angle_hinge),
    gm.translation3(x_child_in_hinge, 0, z_child_in_hinge))
# we don't care about the location in y
fwd_kinematic_hinge_residual_tf = gm.speed_up(
    gm.dot(gm.diag(1, 0, 1, 1), fwd_kinematic_hinge),
    gm.free_symbols(fwd_kinematic_hinge))


def compute_y_hinge_axis_residual(x, angle_tf):
    """Computes the residual for an estimate of the hinge locations on the nobilia shelf
    
    Args:
        x (np.ndarray): [xh, zh, xc, zc] x and z locations of hinge in parent and child in hinge
        angle_1_tf (TYPE): list of tuples (a, tf) where a is the angle of the top panel relative to the parent
    """
    param_dict = {
        str(x_hinge_in_parent): x[0],
        str(z_hinge_in_parent): x[1],
        str(x_child_in_hinge): x[2],
        str(z_child_in_hinge): x[3]
    }
    def __init__(self, km, observations, transition_rules=None, max_iterations=20, num_samples=7):
        """Sets up an EKF estimating the underlying state of a set of observations.
        
        Args:
            km (ArticulationModel): Articulation model to query for constraints
            observations (dict): A dict of observations. Names are mapped to 
                                 any kind of symbolic expression/matrix
            transition_rules (dict, optional): Maps symbols to their transition rule.
                                               Rules will be generated automatically, if not provided here.
        """
        state_vars = union([gm.free_symbols(o) for o in observations.values()])

        self.num_samples = num_samples

        self.ordered_vars,  \
        self.transition_fn, \
        self.transition_args = generate_transition_function(QPStateModel.DT_SYM, 
                                                            state_vars, 
                                                            transition_rules)
        self.command_vars = {s for s in self.transition_args 
                                if s not in state_vars and str(s) != str(QPStateModel.DT_SYM)}

        obs_constraints = {}
        obs_switch_vars = {}

        # State as column vector n * 1
        self.switch_vars = {}
        self._obs_state  = {}
        self.obs_vars  = {}
        self.takers = {}
        flat_obs    = []
        for o_label, o in sorted(observations.items()):
            if gm.is_symbolic(o):
                obs_switch_var = gm.Symbol(f'{o_label}_observed')
                self.switch_vars[o_label] = obs_switch_var
                if o_label not in obs_constraints:
                    obs_constraints[o_label] = {}
                if o_label not in self.obs_vars:
                    self.obs_vars[o_label] = []

                if gm.is_matrix(o):
                    if type(o) == gm.GM:
                        components = zip(sum([[(y, x) for x in range(o.shape[1])] 
                                                      for y in range(o.shape[0])], []), iter(o))
                    else:
                        components = zip(sum([[(y, x) for x in range(o.shape[1])] 
                                                      for y in range(o.shape[0])], []), o.T.elements()) # Casadi iterates vertically
                    indices = []
                    for coords, c in components:
                        if gm.is_symbolic(c):
                            obs_symbol = gm.Symbol('{}_{}_{}'.format(o_label, *coords))
                            obs_error  = gm.abs(obs_symbol - c)
                            constraint = SC(-obs_error - (1 - obs_switch_var) * 1e3,
                                            -obs_error + (1 - obs_switch_var) * 1e3, 1, obs_error)
                            obs_constraints[o_label][f'{o_label}:{Path(obs_symbol)}'] = constraint
                            self.obs_vars[o_label].append(obs_symbol)
                            indices.append(coords[0] * o.shape[1] + coords[1])

                    if len(indices) > 0:
                        self.takers[o_label] = indices
                else:
                    obs_symbol = gm.Symbol(f'{o_label}_value')
                    obs_error  = gm.abs(obs_symbol - c)
                    constraint = SC(-obs_error - obs_switch_var * 1e9, 
                                    -obs_error + obs_switch_var * 1e9, 1, obs_error)
                    obs_constraints[o_label][f'{o_label}:{Path(obs_symbol)}'] = constraint

                    self.obs_vars[o_label].append(obs_symbol)
                    self.takers[o_label] = [0]

        state_constraints = km.get_constraints_by_symbols(state_vars)

        cvs, hard_constraints = generate_controlled_values(state_constraints, 
                                                           {gm.DiffSymbol(s) for s in state_vars 
                                                                             if gm.get_symbol_type(s) != gm.TYPE_UNKNOWN})
        flat_obs_constraints = dict(sum([list(oc.items()) for oc in obs_constraints.values()], []))

        self.qp = TQPB(hard_constraints, flat_obs_constraints, cvs)

        st_bound_vars, st_bounds, st_unbounded = static_var_bounds(km, state_vars)
        self._state = {s: 0 for s in st_unbounded} # np.random.uniform(-1.0, 1.0) for s in st_unbounded}

        for vb, (lb, ub) in zip(st_bound_vars, st_bounds):
            self._state[vb] = np.random.uniform(lb, ub)

        self._state_buffer = []
        self._state.update({s: 0 for s in self.transition_args})
        self._obs_state = {s: 0 for s in sum(self.obs_vars.values(), [])}
        self._obs_count = 0
        self._stamp_last_integration = None
        self._max_iterations = 10
        self._current_error  = 1e9
Example #13
0
    def __init__(self,
                 km,
                 actuated_object_path,
                 target_object_path,
                 controlled_symbols,
                 start_state,
                 camera_path=None,
                 navigation_method='cross',
                 visualizer=None,
                 weight_override=None,
                 collision_avoidance_paths=None):
        print(f'{actuated_object_path}\n{target_object_path}')

        actuated_object = km.get_data(actuated_object_path)
        target_object = km.get_data(target_object_path)

        all_controlled_symbols = controlled_symbols.union({
            gm.DiffSymbol(j)
            for j in gm.free_symbols(target_object.pose)
            if 'location' not in str(j)
        })
        static_symbols = {
            s
            for s in gm.free_symbols(target_object.pose)
            if 'location' in str(s)
        }

        # Generate push problem
        constraints, \
        geom_distance, \
        coll_world, \
        self.p_internals = generate_push_closing(km,
                                                 start_state,
                                                 all_controlled_symbols,
                                                 actuated_object.pose,
                                                 target_object.pose,
                                                 actuated_object_path,
                                                 target_object_path,
                                                 navigation_method,
                                                 static_symbols=static_symbols)

        start_state.update({s: 0.0 for s in gm.free_symbols(coll_world)})

        weight_override = {} if weight_override is None else weight_override

        controlled_values, \
        constraints = generate_controlled_values(constraints,
                                                 all_controlled_symbols)
        controlled_values = depth_weight_controlled_values(km,
                                                           controlled_values,
                                                           exp_factor=1.1)

        goal_constraints = {
            'reach_point': PIDC(geom_distance, geom_distance, 1, k_i=0.00)
        }

        for s, w in weight_override.items():
            for cv in controlled_values.values():
                if cv.symbol is s:
                    cv.weight_id = w
                    break

        # CAMERA STUFF
        if camera_path is not None:
            camera = km.get_data(camera_path)
            cam_pos = gm.pos_of(camera.pose)
            cam_to_obj = gm.pos_of(target_object.pose) - cam_pos
            cam_forward = gm.dot(camera.pose, gm.vector3(1, 0, 0))
            look_goal = 1 - (gm.dot_product(cam_to_obj, cam_forward) /
                             gm.norm(cam_to_obj))
            goal_constraints['look_at_obj'] = SC(-look_goal, -look_goal, 1,
                                                 look_goal)

        # GOAL CONSTAINT GENERATION
        # 'avoid_collisions': SC.from_constraint(closest_distance_constraint_world(eef_pose, eef_path[:-1], 0.03), 100)
        # }

        if collision_avoidance_paths is not None:
            for p in collision_avoidance_paths:
                obj = km.get_data(p)
                goal_constraints[f'avoid_collision {p}'] = SC.from_constraint(
                    closest_distance_constraint(actuated_object.pose, obj.pose,
                                                actuated_object_path, p, 0.01),
                    100)

        goal_constraints.update({
            f'open_object_{x}': PIDC(s, s, 1)
            for x, s in enumerate(gm.free_symbols(target_object.pose))
        })

        self.look_goal = look_goal if camera_path is not None else None
        self.in_contact = gm.less_than(geom_distance, 0.01)
        self.controlled_values = controlled_values
        self.geom_distance = geom_distance

        self.qpb = GQPB(coll_world,
                        constraints,
                        goal_constraints,
                        controlled_values,
                        visualizer=visualizer)
        self.qpb._cb_draw = self.p_internals.f_debug_draw
    # c_avoidance_constraints = {f'collision avoidance {name}': SC.from_constraint(closest_distance_constraint_world(gm.get_data(Path(name) + ('pose',)),
    #                                                                              Path(name),
    #                                                                              0.03), 100) for name in active_robot_world.names}

    print('\n'.join([str(s) for s in robot_controlled_symbols]))

    n_iter = []
    total_dur = []

    for part_path in [Path(f'kitchen/links/{p}') for p in kitchen_parts]:
        # for part_path in [Path(f'nobilia/links/handle')]:
        print(f'Planning trajectory for "{part_path}"')
        printed_exprs = {}
        obj = km.get_data(part_path)

        start_state = {s: 0.7 for s in gm.free_symbols(obj.pose)}

        active_parts_to_avoid = [
            p for p in km.get_active_geometry_raw(gm.free_symbols(
                obj.pose)).keys() if p != part_path
        ]

        weights = None
        if isinstance(base_joint, DiffDriveJoint):
            weights = {}
            weights[base_joint.l_wheel_vel] = 0.001
            weights[base_joint.r_wheel_vel] = 0.001

        if args.vis_plan == 'during':
            pushing_controller = PushingController(
                km,
Example #15
0
    def __init__(self,
                 km,
                 paths_observables,
                 transition_rules=None,
                 num_samples=10):
        """Initializes the tracker to estimate variables based 
           on the given paths. The paths are assumed to point to
           6D poses.
        
        Args:
            km (ArticulationModel): Articulation model to used
            paths_observables (list): List of paths to poses that will be observed
            noise_estimation_observations (int): Number of observations to collect before initializing the EKFs
            estimate_init_steps (int): Number of steps used to initialize the estimate of an ekf
        """
        poses = {p: km.get_data(p) for p in paths_observables}
        poses = {
            str(p): pose.pose if isinstance(pose, Frame) else pose
            for p, pose in poses.items()
        }
        # obs_features = {p: generate_6d_feature(pose) for p, pose in poses.items()}
        obs_features = {p: pose for p, pose in poses.items()}

        # Identify tracking pools. All poses within one pool share at least one DoF
        tracking_pools = [(gm.free_symbols(feature), [(p, feature)])
                          for p, feature in obs_features.items()
                          if len(gm.free_symbols(feature)) != 0]

        final_pools = []
        while len(tracking_pools) > 0:
            syms, feature_list = tracking_pools[0]
            initial_syms_size = len(syms)
            y = 1
            while y < len(tracking_pools):
                o_syms, o_feature_list = tracking_pools[y]
                if len(syms.intersection(o_syms)) != 0:
                    syms = syms.union(o_syms)
                    feature_list += o_feature_list
                    del tracking_pools[y]
                else:
                    y += 1

            # If the symbol set has not been enlarged,
            # there is no more overlap with other pools
            if len(syms) == initial_syms_size:
                final_pools.append((syms, feature_list))
                tracking_pools = tracking_pools[1:]
            else:
                tracking_pools[0] = (syms, feature_list)

        tracking_pools = final_pools
        self.estimators = [
            QPStateModel(km,
                         dict(features),
                         transition_rules=transition_rules,
                         num_samples=num_samples)
            for symbols, features in tracking_pools
        ]

        print(f'Generated {len(self.estimators)} Estimators:\n  '
              '\n  '.join(str(e) for e in self.estimators))

        self.observation_names = [str(p) for p in paths_observables]
def main(create_figure=False,
         vis_mode=False,
         log_csv=True,
         min_n_dof=1,
         samples=300,
         n_observations=25,
         noise_lin=0.2,
         noise_ang=30,
         noise_steps=5):

    wait_duration = rospy.Duration(0.1)

    vis = ROSBPBVisualizer('ekf_vis', 'world') if vis_mode != 'none' else None
    km = GeometryModel()

    with open(res_pkg_path('package://iai_kitchen/urdf_obj/IAI_kitchen.urdf'),
              'r') as urdf_file:
        urdf_kitchen_str = urdf_file.read()
        kitchen_model = urdf_filler(
            URDF.from_xml_string(hacky_urdf_parser_fix(urdf_kitchen_str)))
        load_urdf(km, Path('kitchen'), kitchen_model)

    km.clean_structure()
    km.dispatch_events()

    kitchen = km.get_data('kitchen')

    tracking_pools = []
    for name, link in kitchen.links.items():
        symbols = gm.free_symbols(link.pose)
        if len(symbols) == 0:
            continue

        for x in range(len(tracking_pools)):
            syms, l = tracking_pools[x]
            if len(symbols.intersection(syms)
                   ) != 0:  # BAD ALGORITHM, DOES NOT CORRECTLY IDENTIFY SETS
                tracking_pools[x] = (syms.union(symbols),
                                     l + [(name, link.pose)])
                break
        else:
            tracking_pools.append((symbols, [(name, link.pose)]))

    # tracking_pools = [tracking_pools[7]]
    # print('Identified {} tracking pools:\n{}'.format(len(tracking_pools), tracking_pools))

    all_ekfs = [
        EKFModel(dict(poses), km.get_constraints_by_symbols(symbols))
        for symbols, poses in tracking_pools
    ]  # np.eye(len(symbols)) * 0.001
    print('Created {} EKF models'.format(len(all_ekfs)))
    print('\n'.join(str(e) for e in all_ekfs))

    # Sanity constraint
    min_n_dof = min(min_n_dof, len(all_ekfs))

    iteration_times = []

    for u in range(min_n_dof, len(all_ekfs) + 1):
        if rospy.is_shutdown():
            break

        ekfs = all_ekfs[:u]

        observed_poses = {}
        for ekf in ekfs:
            for link_name, _ in ekf.takers:
                observed_poses[link_name] = kitchen.links[link_name].pose
        names, poses = zip(*sorted(observed_poses.items()))

        state_symbols = union([gm.free_symbols(p) for p in poses])
        ordered_state_vars = [
            s for _, s in sorted((str(s), s) for s in state_symbols)
        ]

        state_constraints = {}
        for n, c in km.get_constraints_by_symbols(state_symbols).items():
            if gm.is_symbol(c.expr):
                s = gm.free_symbols(c.expr).pop()
                fs = gm.free_symbols(c.lower).union(gm.free_symbols(c.upper))
                if len(fs.difference({s})) == 0:
                    state_constraints[s] = (float(gm.subs(c.lower, {s: 0})),
                                            float(gm.subs(c.upper, {s: 0})))

        state_bounds = np.array([
            state_constraints[s]
            if s in state_constraints else [-np.pi * 0.5, np.pi * 0.5]
            for s in ordered_state_vars
        ])

        state_fn = gm.speed_up(gm.vstack(*poses), ordered_state_vars)
        subworld = km.get_active_geometry(state_symbols)

        # Generate observation noise
        print('Generating R matrices...')
        n_cov_obs = 400
        full_log = []

        dof_iters = []

        # EXPERIMENT
        for lin_std, ang_std in [(noise_lin, noise_ang * (np.pi / 180.0))]:
            # zip(np.linspace(0, noise_lin, noise_steps),
            #     np.linspace(0, noise_ang * (np.pi / 180.0), noise_steps)):
            if rospy.is_shutdown():
                break
            # INITIALIZE SENSOR MODEL
            training_obs = []
            state = np.random.uniform(state_bounds.T[0], state_bounds.T[1])
            observations = state_fn.call2(state)

            for _ in range(n_cov_obs):
                noisy_obs = {}
                for x, noise in enumerate([
                        t.dot(r) for t, r in zip(
                            random_normal_translation(len(poses), 0, lin_std),
                            random_rot_normal(len(poses), 0, ang_std))
                ]):
                    noisy_obs[names[x]] = observations[x * 4:x * 4 +
                                                       4, :4].dot(noise)
                training_obs.append(noisy_obs)

            for ekf in ekfs:
                ekf.generate_R(training_obs)
                # ekf.set_R(np.eye(len(ekf.ordered_vars)) * 0.1)

            # Generate figure
            gridsize = (4, samples)
            plot_size = (4, 4)
            fig = plt.figure(figsize=(gridsize[1] * plot_size[0], gridsize[0] *
                                      plot_size[1])) if create_figure else None

            gt_states = []
            states = [[] for x in range(samples)]
            variances = [[] for x in range(samples)]
            e_obs = [[] for x in range(samples)]

            print('Starting iterations')
            for k in tqdm(range(samples)):
                if rospy.is_shutdown():
                    break

                state = np.random.uniform(state_bounds.T[0], state_bounds.T[1])
                gt_states.append(state)
                observations = state_fn.call2(state).copy()
                gt_obs_d = {
                    n: observations[x * 4:x * 4 + 4, :4]
                    for x, n in enumerate(names)
                }
                subworld.update_world(dict(zip(ordered_state_vars, state)))

                if vis_mode == 'iter' or vis_mode == 'io':
                    vis.begin_draw_cycle('gt', 'noise', 'estimate', 't_n',
                                         't0')
                    vis.draw_world('gt', subworld, g=0, b=0)
                    vis.render('gt')

                estimates = []
                for ekf in ekfs:
                    particle = ekf.spawn_particle()
                    estimates.append(particle)

                initial_state = dict(
                    sum([[(s, v) for s, v in zip(ekf.ordered_vars, e.state)]
                         for e, ekf in zip(estimates, ekfs)], []))
                initial_state = np.array(
                    [initial_state[s] for s in ordered_state_vars])
                if initial_state.min() < state_bounds.T[0].min(
                ) or initial_state.max() > state_bounds.T[1].max():
                    raise Exception(
                        'Estimate initialization is out of bounds: {}'.format(
                            np.vstack([initial_state, state_bounds.T]).T))
                initial_delta = state - initial_state

                for y in range(n_observations):
                    # Add noise to observations
                    noisy_obs = {}
                    for x, noise in enumerate([
                            t.dot(r) for t, r in zip(
                                random_normal_translation(
                                    len(poses), 0, lin_std),
                                random_rot_normal(len(poses), 0, ang_std))
                    ]):
                        noisy_obs[names[x]] = observations[x * 4:x * 4 +
                                                           4, :4].dot(noise)

                    if vis_mode in {'iter', 'iter-trail'} or (vis_mode == 'io'
                                                              and y == 0):
                        for n, t in noisy_obs.items():
                            subworld.named_objects[Path(
                                ('kitchen', 'links', n))].np_transform = t
                        if vis_mode != 'iter-trail':
                            vis.begin_draw_cycle('noise')
                        vis.draw_world('noise', subworld, r=0, g=0, a=0.1)
                        vis.render('noise')

                    start_time = time()
                    for estimate, ekf in zip(estimates, ekfs):
                        if y > 0:
                            control = np.zeros(len(ekf.ordered_controls))
                            estimate.state, estimate.cov = ekf.predict(
                                estimate.state.flatten(), estimate.cov,
                                control)
                            obs_vector = ekf.gen_obs_vector(noisy_obs)
                            estimate.state, estimate.cov = ekf.update(
                                estimate.state, estimate.cov,
                                ekf.gen_obs_vector(noisy_obs))

                            if vis_mode in {'iter', 'iter-trail'}:
                                subworld.update_world({
                                    s: v
                                    for s, v in zip(ekf.ordered_vars,
                                                    estimate.state)
                                })
                        else:
                            obs_vector = ekf.gen_obs_vector(noisy_obs)

                            for _ in range(1):
                                h_prime = ekf.h_prime_fn.call2(estimate.state)
                                obs_delta = obs_vector.reshape(
                                    (len(obs_vector), 1)) - ekf.h_fn.call2(
                                        estimate.state)
                                estimate.state += (h_prime.T.dot(obs_delta) *
                                                   0.1).reshape(
                                                       estimate.state.shape)

                            if vis_mode in {'iter', 'io'}:
                                subworld.update_world({
                                    s: v
                                    for s, v in zip(ekf.ordered_vars,
                                                    estimate.state)
                                })

                    if vis_mode != 'none' and y == 0:
                        vis.draw_world('t0', subworld, b=0, a=1)
                        vis.render('t0')
                    elif vis_mode in {'iter', 'iter-trail'}:
                        if vis_mode != 'iter-trail':
                            vis.begin_draw_cycle('t_n')
                        vis.draw_world('t_n', subworld, b=0, a=1)
                        vis.render('t_n')

                    if log_csv or fig is not None:
                        e_state_d = dict(
                            sum([[(s, v)
                                  for s, v in zip(ekf.ordered_vars, e.state)]
                                 for e, ekf in zip(estimates, ekfs)], []))
                        covs = dict(
                            sum([[(s, v) for s, v in zip(
                                ekf.ordered_vars, np.sqrt(np.trace(e.cov)))]
                                 for e, ekf in zip(estimates, ekfs)], []))
                        e_state = np.hstack([
                            e_state_d[s] for s in ordered_state_vars
                        ]).reshape((len(e_state_d), ))

                        if log_csv:
                            full_log.append(
                                np.hstack(
                                    ([lin_std,
                                      ang_std], state, e_state.flatten(),
                                     np.array([
                                         covs[s] for s in ordered_state_vars
                                     ]))))

                        if fig is not None:
                            e_obs[k].append(
                                np.array([
                                    np.abs(
                                        ekf.gen_obs_vector(gt_obs_d) -
                                        ekf.h_fn.call2(e.state)).max()
                                    for e, ekf in zip(estimates, ekfs)
                                ]))
                            states[k].append(e_state)
                            variances[k].append(
                                np.array([covs[s]
                                          for s in ordered_state_vars]))
                else:
                    if vis_mode == 'io':
                        for estimate, ekf in zip(estimates, ekfs):
                            subworld.update_world({
                                s: v
                                for s, v in zip(ekf.ordered_vars,
                                                estimate.state)
                            })

                        vis.draw_world('t_n', subworld, r=0, b=0, a=1)
                        vis.render('t_n')

                    dof_iters.append(time() - start_time)

            if fig is not None:
                axes = [
                    plt.subplot2grid(gridsize, (y, 0), colspan=1, rowspan=1)
                    for y in range(gridsize[0])
                ]
                axes = np.array(
                    sum([[
                        plt.subplot2grid(gridsize, (y, x),
                                         colspan=1,
                                         rowspan=1,
                                         sharey=axes[y])
                        for y in range(gridsize[0])
                    ] for x in range(1, gridsize[1])], axes)).reshape(
                        (gridsize[1], gridsize[0]))

                for x, (gt_s, state, variance, obs_delta,
                        (ax_s, ax_d, ax_o, ax_v)) in enumerate(
                            zip(gt_states, states, variances, e_obs, axes)):

                    for y in gt_s:
                        ax_s.axhline(y, xmin=0.97, xmax=1.02)

                    ax_s.set_title('State; Sample: {}'.format(x))
                    ax_d.set_title('Delta from GT; Sample: {}'.format(x))
                    ax_o.set_title('Max Delta in Obs; Sample: {}'.format(x))
                    ax_v.set_title('Standard Deviation; Sample: {}'.format(x))
                    ax_s.plot(state)
                    ax_d.plot(gt_s - np.vstack(state))
                    ax_o.plot(obs_delta)
                    ax_v.plot(variance)
                    ax_s.grid(True)
                    ax_d.grid(True)
                    ax_o.grid(True)
                    ax_v.grid(True)

                fig.tight_layout()
                plt.savefig(
                    res_pkg_path(
                        'package://kineverse_experiment_world/test/ekf_object_tracker_{}_{}.png'
                        .format(lin_std, ang_std)))

        iteration_times.append(dof_iters)

        if log_csv:
            df = pd.DataFrame(
                columns=['lin_std', 'ang_std'] +
                ['gt_{}'.format(x) for x in range(len(state_symbols))] +
                ['ft_{}'.format(x) for x in range(len(state_symbols))] +
                ['var_{}'.format(x) for x in range(len(state_symbols))],
                data=full_log)
            df.to_csv(res_pkg_path(
                'package://kineverse_experiment_world/test/ekf_object_tracker.csv'
            ),
                      index=False)

    df = pd.DataFrame(
        columns=[str(x) for x in range(1,
                                       len(iteration_times) + 1)],
        data=np.vstack(iteration_times).T)
    df.to_csv(res_pkg_path(
        'package://kineverse_experiment_world/test/ekf_object_tracker_performance.csv'
    ),
              index=False)
    km = GeometryModel()
    vis = ROSBPBVisualizer('kineverse/nobilia/vis', base_frame='world')

    origin_pose = gm.translation3(x_loc_sym, 0, 0)

    debug = create_nobilia_shelf(km, Path('nobilia'), origin_pose)

    km.clean_structure()
    km.dispatch_events()

    shelf = km.get_data('nobilia')

    shelf_pos = shelf.joints['hinge'].position

    world = km.get_active_geometry({shelf_pos
                                    }.union(gm.free_symbols(origin_pose)))

    params = debug.tuning_params

    with dpg.window(label='Parameter settings'):
        for s, p in debug.tuning_params.items():

            def update_param(sender, value, symbol):
                params[symbol] = value
                draw_shelves(shelf, params, world, vis, steps=5)

            slider = dpg.add_slider_float(label=f'{s}',
                                          id=f'{s}',
                                          callback=update_param,
                                          user_data=s,
                                          min_value=p - 0.1,
    door_x, door_y = [gm.Position(f'localization_{x}') for x in 'xy']

    create_door(km,
                Path('door'),
                0.5,
                0.35,
                to_world_tf=gm.translation3(door_x, door_y, 0.1))

    km.clean_structure()
    km.dispatch_events()

    door = km.get_data('door')
    handle = door.links['handle']
    iiwa = km.get_data('iiwa')
    symbols = gm.free_symbols(door.links['handle'].pose).union(
        gm.free_symbols(iiwa.links['link_7'].pose))

    door_position = door.joints['hinge'].position
    handle_position = door.joints['handle'].position

    # Fun for visuals
    world = km.get_active_geometry(symbols)
    symbols = world.free_symbols

    eef = iiwa.links['wsg_50_tool_frame']

    goal_pose = gm.dot(handle.pose, gm.translation3(-0.08, 0.1, 0),
                       gm.rotation3_rpy(0, math.pi * 0.5, 0))

    ik_solver = IKSolver(km, eef.pose, visualizer)