示例#1
0
 def start_swing_foot(self):
     """
     Initialize swing foot interpolator for single-support state.
     """
     self.swing_start = self.swing_foot.pose
     self.swing_interp = SwingFoot(self.swing_foot,
                                   self.swing_target,
                                   self.ssp_duration,
                                   takeoff_clearance=0.05,
                                   landing_clearance=0.05)
示例#2
0
class WalkingFSM(pymanoid.Process):
    """
    Finite State Machine for biped walking.

    Parameters
    ----------
    ssp_duration : scalar
        Duration of single-support phases, in [s].
    dsp_duration : scalar
        Duration of double-support phases, in [s].
    """
    def __init__(self, ssp_duration, dsp_duration):
        super(WalkingFSM, self).__init__()
        self.dsp_duration = dsp_duration
        self.mpc_timestep = round(0.1 / dt) * dt  # update MPC every ~0.1 [s]
        self.next_footstep = 2
        self.ssp_duration = ssp_duration
        self.state = None
        #
        self.start_standing()

    def on_tick(self, sim):
        """
        Update function run at every simulation tick.

        Parameters
        ----------
        sim : Simulation
            Instance of the current simulation.
        """
        if self.state == "Standing":
            return self.run_standing()
        elif self.state == "DoubleSupport":
            return self.run_double_support()
        elif self.state == "SingleSupport":
            return self.run_single_support()
        raise Exception("Unknown state: " + self.state)

    def start_standing(self):
        """
        Switch to standing state.
        """
        self.start_walking = False
        self.state = "Standing"
        return self.run_standing()

    def run_standing(self):
        """
        Run standing state.
        """
        if self.start_walking:
            self.start_walking = False
            if self.next_footstep < len(footsteps):
                return self.start_double_support()

    def start_double_support(self):
        """
        Switch to double-support state.
        """
        if self.next_footstep % 2 == 1:  # left foot swings
            self.stance_foot = stance.right_foot
        else:  # right foot swings
            self.stance_foot = stance.left_foot
        dsp_duration = self.dsp_duration
        if self.next_footstep == 2 or self.next_footstep == len(footsteps) - 1:
            # double support is a bit longer for the first and last steps
            dsp_duration = 4 * self.dsp_duration
        self.swing_target = footsteps[self.next_footstep]
        self.rem_time = dsp_duration
        self.state = "DoubleSupport"
        self.start_com_mpc_dsp()
        return self.run_double_support()

    def start_com_mpc_dsp(self):
        self.update_mpc(self.rem_time, self.ssp_duration)

    def run_double_support(self):
        """
        Run double-support state.
        """
        if self.rem_time <= 0.:
            return self.start_single_support()
        self.run_com_mpc()
        self.rem_time -= dt

    def start_single_support(self):
        """
        Switch to single-support state.
        """
        if self.next_footstep % 2 == 1:  # left foot swings
            self.swing_foot = stance.free_contact('left_foot')
        else:  # right foot swings
            self.swing_foot = stance.free_contact('right_foot')
        self.next_footstep += 1
        self.rem_time = self.ssp_duration
        self.state = "SingleSupport"
        self.start_swing_foot()
        self.start_com_mpc_ssp()
        return self.run_single_support()

    def start_swing_foot(self):
        """
        Initialize swing foot interpolator for single-support state.
        """
        self.swing_start = self.swing_foot.pose
        self.swing_interp = SwingFoot(self.swing_foot,
                                      self.swing_target,
                                      self.ssp_duration,
                                      takeoff_clearance=0.05,
                                      landing_clearance=0.05)

    def start_com_mpc_ssp(self):
        self.update_mpc(0., self.rem_time)

    def run_single_support(self):
        """
        Run single-support state.
        """
        if self.rem_time <= 0.:
            stance.set_contact(self.swing_foot)
            if self.next_footstep < len(footsteps):
                return self.start_double_support()
            else:  # footstep sequence is over
                return self.start_standing()
        self.run_swing_foot()
        self.run_com_mpc()
        self.rem_time -= dt

    def run_swing_foot(self):
        """
        Run swing foot interpolator for single-support state.
        """
        self.swing_foot.set_pose(self.swing_interp.integrate(dt))

    def update_mpc(self, dsp_duration, ssp_duration):
        nb_preview_steps = 16
        T = self.mpc_timestep
        nb_init_dsp_steps = int(round(dsp_duration / T))
        nb_init_ssp_steps = int(round(ssp_duration / T))
        nb_dsp_steps = int(round(self.dsp_duration / T))
        A = array([[1., T, T**2 / 2.], [0., 1., T], [0., 0., 1.]])
        B = array([T**3 / 6., T**2 / 2., T]).reshape((3, 1))
        h = stance.com.z
        g = -sim.gravity[2]
        zmp_from_state = array([1., 0., -h / g])
        C = array([+zmp_from_state, -zmp_from_state])
        D = None
        e = [[], []]
        cur_vertices = self.stance_foot.get_scaled_contact_area(0.9)
        next_vertices = self.swing_target.get_scaled_contact_area(0.9)
        for coord in [0, 1]:
            cur_max = max(v[coord] for v in cur_vertices)
            cur_min = min(v[coord] for v in cur_vertices)
            next_max = max(v[coord] for v in next_vertices)
            next_min = min(v[coord] for v in next_vertices)
            e[coord] = [
                array([+1000., +1000.]) if i < nb_init_dsp_steps else
                array([+cur_max, -cur_min]) if i - nb_init_dsp_steps <=
                nb_init_ssp_steps else array([+1000., +1000.]) if i -
                nb_init_dsp_steps - nb_init_ssp_steps < nb_dsp_steps else
                array([+next_max, -next_min]) for i in range(nb_preview_steps)
            ]
        self.x_mpc = LinearPredictiveControl(
            A,
            B,
            C,
            D,
            e[0],
            x_init=array([stance.com.x, stance.com.xd, stance.com.xdd]),
            x_goal=array([self.swing_target.x, 0., 0.]),
            nb_steps=nb_preview_steps,
            wxt=1.,
            wu=0.01)
        self.y_mpc = LinearPredictiveControl(
            A,
            B,
            C,
            D,
            e[1],
            x_init=array([stance.com.y, stance.com.yd, stance.com.ydd]),
            x_goal=array([self.swing_target.y, 0., 0.]),
            nb_steps=nb_preview_steps,
            wxt=1.,
            wu=0.01)
        self.x_mpc.solve()
        self.y_mpc.solve()
        self.preview_time = 0.

    def plot_mpc_preview(self):
        import pylab
        T = self.mpc_timestep
        h = stance.com.z
        g = -sim.gravity[2]
        trange = [sim.time + k * T for k in range(len(self.x_mpc.X))]
        pylab.ion()
        pylab.clf()
        pylab.subplot(211)
        pylab.plot(trange, [v[0] for v in self.x_mpc.X])
        pylab.plot(trange, [v[0] - v[2] * h / g for v in self.x_mpc.X])
        pylab.subplot(212)
        pylab.plot(trange, [v[0] for v in self.y_mpc.X])
        pylab.plot(trange, [v[0] - v[2] * h / g for v in self.y_mpc.X])

    def run_com_mpc(self):
        """
        Run CoM predictive control for single-support state.
        """
        if self.preview_time >= self.mpc_timestep:
            if self.state == "DoubleSupport":
                self.update_mpc(self.rem_time, self.ssp_duration)
            else:  # self.state == "SingleSupport":
                self.update_mpc(0., self.rem_time)
        com_jerk = array([self.x_mpc.U[0][0], self.y_mpc.U[0][0], 0.])
        stance.com.integrate_constant_jerk(com_jerk, dt)
        self.preview_time += dt