Example #1
0
    def _convert(self, symbol, t, y, y_dot, inputs):
        """ See :meth:`CasadiConverter.convert()`. """
        if isinstance(
            symbol,
            (
                pybamm.Scalar,
                pybamm.Array,
                pybamm.Time,
                pybamm.InputParameter,
                pybamm.ExternalVariable,
            ),
        ):
            return casadi.MX(symbol.evaluate(t, y, y_dot, inputs))

        elif isinstance(symbol, pybamm.StateVector):
            if y is None:
                raise ValueError("Must provide a 'y' for converting state vectors")
            return casadi.vertcat(*[y[y_slice] for y_slice in symbol.y_slices])

        elif isinstance(symbol, pybamm.StateVectorDot):
            if y_dot is None:
                raise ValueError("Must provide a 'y_dot' for converting state vectors")
            return casadi.vertcat(*[y_dot[y_slice] for y_slice in symbol.y_slices])

        elif isinstance(symbol, pybamm.BinaryOperator):
            left, right = symbol.children
            # process children
            converted_left = self.convert(left, t, y, y_dot, inputs)
            converted_right = self.convert(right, t, y, y_dot, inputs)

            if isinstance(symbol, pybamm.Minimum):
                return casadi.fmin(converted_left, converted_right)
            if isinstance(symbol, pybamm.Maximum):
                return casadi.fmax(converted_left, converted_right)

            # _binary_evaluate defined in derived classes for specific rules
            return symbol._binary_evaluate(converted_left, converted_right)

        elif isinstance(symbol, pybamm.UnaryOperator):
            converted_child = self.convert(symbol.child, t, y, y_dot, inputs)
            if isinstance(symbol, pybamm.AbsoluteValue):
                return casadi.fabs(converted_child)
            return symbol._unary_evaluate(converted_child)

        elif isinstance(symbol, pybamm.Function):
            converted_children = [
                self.convert(child, t, y, y_dot, inputs) for child in symbol.children
            ]
            # Special functions
            if symbol.function == np.min:
                return casadi.mmin(*converted_children)
            elif symbol.function == np.max:
                return casadi.mmax(*converted_children)
            elif symbol.function == np.abs:
                return casadi.fabs(*converted_children)
            elif symbol.function == np.sqrt:
                return casadi.sqrt(*converted_children)
            elif symbol.function == np.sin:
                return casadi.sin(*converted_children)
            elif symbol.function == np.arcsinh:
                return casadi.arcsinh(*converted_children)
            elif symbol.function == np.arccosh:
                return casadi.arccosh(*converted_children)
            elif symbol.function == np.tanh:
                return casadi.tanh(*converted_children)
            elif symbol.function == np.cosh:
                return casadi.cosh(*converted_children)
            elif symbol.function == np.sinh:
                return casadi.sinh(*converted_children)
            elif symbol.function == np.cos:
                return casadi.cos(*converted_children)
            elif symbol.function == np.exp:
                return casadi.exp(*converted_children)
            elif symbol.function == np.log:
                return casadi.log(*converted_children)
            elif symbol.function == np.sign:
                return casadi.sign(*converted_children)
            elif isinstance(symbol.function, (PchipInterpolator, CubicSpline)):
                return casadi.interpolant("LUT", "bspline", [symbol.x], symbol.y)(
                    *converted_children
                )
            elif symbol.function.__name__.startswith("elementwise_grad_of_"):
                differentiating_child_idx = int(symbol.function.__name__[-1])
                # Create dummy symbolic variables in order to differentiate using CasADi
                dummy_vars = [
                    casadi.MX.sym("y_" + str(i)) for i in range(len(converted_children))
                ]
                func_diff = casadi.gradient(
                    symbol.differentiated_function(*dummy_vars),
                    dummy_vars[differentiating_child_idx],
                )
                # Create function and evaluate it using the children
                casadi_func_diff = casadi.Function("func_diff", dummy_vars, [func_diff])
                return casadi_func_diff(*converted_children)
            # Other functions
            else:
                return symbol._function_evaluate(converted_children)
        elif isinstance(symbol, pybamm.Concatenation):
            converted_children = [
                self.convert(child, t, y, y_dot, inputs) for child in symbol.children
            ]
            if isinstance(symbol, (pybamm.NumpyConcatenation, pybamm.SparseStack)):
                return casadi.vertcat(*converted_children)
            # DomainConcatenation specifies a particular ordering for the concatenation,
            # which we must follow
            elif isinstance(symbol, pybamm.DomainConcatenation):
                slice_starts = []
                all_child_vectors = []
                for i in range(symbol.secondary_dimensions_npts):
                    child_vectors = []
                    for child_var, slices in zip(
                        converted_children, symbol._children_slices
                    ):
                        for child_dom, child_slice in slices.items():
                            slice_starts.append(symbol._slices[child_dom][i].start)
                            child_vectors.append(
                                child_var[child_slice[i].start : child_slice[i].stop]
                            )
                    all_child_vectors.extend(
                        [v for _, v in sorted(zip(slice_starts, child_vectors))]
                    )
                return casadi.vertcat(*all_child_vectors)

        else:
            raise TypeError(
                """
                Cannot convert symbol of type '{}' to CasADi. Symbols must all be
                'linear algebra' at this stage.
                """.format(
                    type(symbol)
                )
            )
Example #2
0
    def build(self):
        """
        Build the internal nonlinear program (NLP).
        """
        self.nlp = NonlinearProgram(solver='ipopt', options=self.nlp_options)
        foothold, next_foothold = self.foothold, self.next_foothold
        omega2, omega = self.omega2, self.omega
        dcm_target = list(self.dcm_target)
        start_com = list(self.start_com)
        start_comd = list(self.start_comd)
        T = self.nlp.new_variable(
            'T', 1, init=[self.desired_duration],
            lb=[self.dT_min * self.nb_steps], ub=[5. * self.desired_duration])
        p_0 = self.nlp.new_constant('p_0', 3, start_com)
        pd_0 = self.nlp.new_constant('pd_0', 3, start_comd)
        dT = T / self.nb_steps
        p_k, pd_k = p_0, pd_0
        W_comdd = list(self.weights['minimize_comdd'])
        assert len(W_comdd) in [1, 3]

        for k in range(self.nb_steps):
            z_min = list(foothold.p - [0.42, 0.42, 0.42])
            z_max = list(foothold.p + [0.42, 0.42, 0.42])
            pdd_k = self.nlp.new_variable(
                'pdd_%d' % k, 3, init=[0, 0, 0], lb=self.pdd_min,
                ub=self.pdd_max)
            z_k = self.nlp.new_variable(
                'z_%d' % k, 3, init=list(foothold.p), lb=z_min, ub=z_max)

            CZ_k = z_k - foothold.p
            self.nlp.add_equality_constraint(
                pdd_k, self.omega2 * (p_k - z_k) + gravity)
            self.nlp.extend_cost(
                self.weights['center_zmp'] * casadi.dot(CZ_k, CZ_k) * dT)
            self.nlp.extend_cost(
                casadi.dot(pdd_k, W_comdd * pdd_k) * dT)

            # Exact integration by solving the first-order ODE
            p_next = p_k + pd_k / omega * casadi.sinh(omega * dT) \
                + pdd_k / omega2 * (casadi.cosh(omega * dT) - 1.)
            pd_next = pd_k * casadi.cosh(omega * dT) \
                + pdd_k / omega * casadi.sinh(omega * dT)

            self.add_com_height_constraint(p_k, ref_height=0.8, max_dev=0.2)
            self.add_friction_constraint(p_k, z_k, foothold)
            self.add_linear_cop_constraints(p_k, z_k, foothold)

            p_k = self.nlp.new_variable(
                'p_%d' % (k + 1), 3, init=start_com, lb=self.p_min,
                ub=self.p_max)
            pd_k = self.nlp.new_variable(
                'pd_%d' % (k + 1), 3, init=start_comd, lb=self.pd_min,
                ub=self.pd_max)
            self.nlp.add_equality_constraint(p_next, p_k)
            self.nlp.add_equality_constraint(pd_next, pd_k)

        p_last, pd_last = p_k, pd_k
        dcm_last = p_last + pd_last / omega
        cp_last = dcm_last + gravity / omega2
        self.add_friction_constraint(p_last, cp_last, next_foothold)
        self.add_linear_cop_constraints(p_last, cp_last, next_foothold)

        dcm_error = dcm_last - dcm_target
        duration_error = T - self.desired_duration
        self.nlp.extend_cost(
            self.weights['match_dcm'] * casadi.dot(dcm_error, dcm_error))
        self.nlp.extend_cost(
            self.weights['match_duration'] * duration_error ** 2)
        self.nlp.create_solver()
Example #3
0
def traverse(node, casadi_syms, rootnode):
	#print node
	#print node.args
	#print len(node.args)

	if len(node.args)==0:
		# Handle symbols
		if(node.is_Symbol):
			return casadi_syms[node.name]

		# Handle numbers and constants
		if node.is_Zero:
			return 0
		if node.is_Number:
			return float(node)

	trig = sympy.functions.elementary.trigonometric
	if len(node.args)==1:
		# Handle unary operators
		child = traverse(node.args[0], casadi_syms, rootnode) # Recursion!
		if type(node) == trig.cos:
			return casadi.cos(child)
		if type(node) == trig.sin:
			return casadi.sin(child)
		if type(node) == trig.tan:
			return casadi.tan(child)

		if type(node) == trig.cosh:
			return casadi.cosh(child)
		if type(node) == trig.sinh:
			return casadi.sinh(child)
		if type(node) == trig.tanh:
			return casadi.tanh(child)

		if type(node) == trig.cot:
			return 1/casadi.tan(child)
		if type(node) == trig.acos:
			return casadi.arccos(child)
		if type(node) == trig.asin:
			return casadi.arcsin(child)
		if type(node) == trig.atan:
			return casadi.arctan(child)

	if len(node.args)==2:
		# Handle binary operators
		left = traverse(node.args[0], casadi_syms, rootnode) # Recursion!
		right = traverse(node.args[1], casadi_syms, rootnode) # Recursion!
		if node.is_Pow:
			return left**right
		if type(node) == trig.atan2:
			return casadi.arctan2(left,right)

	if len(node.args)>=2:
		# Handle n-ary operators
		child_generator = ( traverse(arg,casadi_syms,rootnode) 
								for arg in node.args )
		if node.is_Add:
			return reduce(lambda x, y: x+y, child_generator)
		if node.is_Mul:
			return reduce(lambda x, y: x*y, child_generator)

	if node!=rootnode:
		raise Exception("No mapping to casadi for node of type " 
				+ str(type(node)))
Example #4
0
def traverse(node, casadi_syms, rootnode):
	#print node
	#print node.args
	#print len(node.args)

	if len(node.args)==0:
		# Handle symbols
		if(node.is_Symbol):
			return casadi_syms[node.name]

		# Handle numbers and constants
		if node.is_Zero:
			return 0
		if node.is_Number:
			return float(node)

	trig = sympy.functions.elementary.trigonometric
	if len(node.args)==1:
		# Handle unary operators
		child = traverse(node.args[0], casadi_syms, rootnode) # Recursion!
		if type(node) == trig.cos:
			return casadi.cos(child)
		if type(node) == trig.sin:
			return casadi.sin(child)
		if type(node) == trig.tan:
			return casadi.tan(child)

		if type(node) == trig.cosh:
			return casadi.cosh(child)
		if type(node) == trig.sinh:
			return casadi.sinh(child)
		if type(node) == trig.tanh:
			return casadi.tanh(child)

		if type(node) == trig.cot:
			return 1/casadi.tan(child)
		if type(node) == trig.acos:
			return casadi.arccos(child)
		if type(node) == trig.asin:
			return casadi.arcsin(child)
		if type(node) == trig.atan:
			return casadi.arctan(child)

	if len(node.args)==2:
		# Handle binary operators
		left = traverse(node.args[0], casadi_syms, rootnode) # Recursion!
		right = traverse(node.args[1], casadi_syms, rootnode) # Recursion!
		if node.is_Pow:
			return left**right
		if type(node) == trig.atan2:
			return casadi.arctan2(left,right)

	if len(node.args)>=2:
		# Handle n-ary operators
		child_generator = ( traverse(arg,casadi_syms,rootnode) 
								for arg in node.args )
		if node.is_Add:
			return reduce(lambda x, y: x+y, child_generator)
		if node.is_Mul:
			return reduce(lambda x, y: x*y, child_generator)

	if node!=rootnode:
		raise Exception("No mapping to casadi for node of type " 
				+ str(type(node)))
Example #5
0
    def __init__(self,
                 nb_steps,
                 com_state,
                 com_target,
                 contact_sequence,
                 omega2=None,
                 swing_duration=None):
        super(COPPredictiveController, self).__init__()
        end_com = list(com_target.p)
        end_comd = list(com_target.pd)
        nb_contacts = len(contact_sequence)
        start_com = list(com_state.p)
        start_comd = list(com_state.pd)

        p_0 = self.nlp.new_constant('p_0', 3, start_com)
        v_0 = self.nlp.new_constant('v_0', 3, start_comd)
        p_k = p_0
        v_k = v_0
        T_swing = 0
        T_total = 0

        for k in xrange(nb_steps):
            contact = contact_sequence[nb_contacts * k / nb_steps]
            u_k = self.nlp.new_variable('u_%d' % k,
                                        3,
                                        init=[0, 0, 0],
                                        lb=self.u_min,
                                        ub=self.u_max)
            dT_k = self.nlp.new_variable('dT_%d' % k,
                                         1,
                                         init=[self.dT_init],
                                         lb=[self.dT_min],
                                         ub=[self.dT_max])
            alpha_k = self.nlp.new_variable('alpha_%d' % k,
                                            1,
                                            init=[0.],
                                            lb=[-self.alpha_lim],
                                            ub=[+self.alpha_lim])
            beta_k = self.nlp.new_variable('beta_%d' % k,
                                           1,
                                           init=[0.],
                                           lb=[-self.beta_lim],
                                           ub=[+self.beta_lim])
            lambda_k = self.nlp.new_variable('lambda_%d' % k,
                                             1,
                                             init=[self.lambda_init],
                                             lb=[self.lambda_min],
                                             ub=[self.lambda_max])

            z_k = contact.p + alpha_k * contact.X * contact.t + \
                beta_k * contact.Y * contact.b
            self.nlp.add_equality_constraint(u_k,
                                             lambda_k * (p_k - z_k) + gravity)
            self.nlp.extend_cost(self.weights['alpha'] * alpha_k * alpha_k *
                                 dT_k)
            self.nlp.extend_cost(self.weights['beta'] * beta_k * beta_k * dT_k)
            # self.nlp.extend_cost(
            #     self.weights['lambda'] * lambda_k ** 2 * dT_k)
            self.nlp.extend_cost(self.weights['u'] * casadi.dot(u_k, u_k) *
                                 dT_k)

            # Full precision (no Taylor expansion)
            omega_k = casadi.sqrt(lambda_k)
            p_next = p_k \
                + v_k / omega_k * casadi.sinh(omega_k * dT_k) \
                + u_k / lambda_k * (cosh(omega_k * dT_k) - 1.)
            v_next = v_k * cosh(omega_k * dT_k) \
                + u_k / omega_k * sinh(omega_k * dT_k)
            T_total = T_total + dT_k
            if 2 * k < nb_steps:
                T_swing = T_swing + dT_k

            self.add_friction_constraint(contact, p_k, z_k)
            self.add_friction_constraint(contact, p_next, z_k)
            # slower:
            # add_linear_friction_constraints(contact, p_k, z_k)
            # add_linear_friction_constraints(contact, p_next, z_k)

            p_k = self.nlp.new_variable('p_%d' % (k + 1),
                                        3,
                                        init=start_com,
                                        lb=self.p_min,
                                        ub=self.p_max)
            v_k = self.nlp.new_variable('v_%d' % (k + 1),
                                        3,
                                        init=start_comd,
                                        lb=self.v_min,
                                        ub=self.v_max)
            self.nlp.add_equality_constraint(p_next, p_k)
            self.nlp.add_equality_constraint(v_next, v_k)

        self.nlp.add_constraint(T_swing,
                                lb=[swing_duration],
                                ub=[100],
                                name='T_swing')

        p_last, v_last = p_k, v_k
        p_diff = p_last - end_com
        v_diff = v_last - end_comd
        self.nlp.extend_cost(self.weights['p'] * casadi.dot(p_diff, p_diff))
        self.nlp.extend_cost(self.weights['v'] * casadi.dot(v_diff, v_diff))
        self.nlp.extend_cost(self.weights['t'] * T_total)
        self.nlp.create_solver()
        #
        self.com_target = com_target
        self.end_com = array(end_com)
        self.end_comd = array(end_comd)
        self.nb_steps = nb_steps
        self.preview = ZMPPreviewBuffer(contact_sequence)
Example #6
0
    def __init__(self,
                 nb_steps,
                 state_estimator,
                 com_target,
                 contact_sequence,
                 omega2,
                 swing_duration=None):
        super(FIPPredictiveController, self).__init__()
        t_build_start = time()
        omega = sqrt(omega2)
        end_com = list(com_target.p)
        end_comd = list(com_target.pd)
        nb_contacts = len(contact_sequence)
        start_com = list(state_estimator.com)
        start_comd = list(state_estimator.comd)

        p_0 = self.nlp.new_constant('p_0', 3, start_com)
        v_0 = self.nlp.new_constant('v_0', 3, start_comd)
        p_k = p_0
        v_k = v_0
        T_swing = 0
        T_total = 0

        for k in xrange(nb_steps):
            contact = contact_sequence[nb_contacts * k / nb_steps]
            z_min = list(contact.p - [1, 1, 1])  # TODO: smarter
            z_max = list(contact.p + [1, 1, 1])
            u_k = self.nlp.new_variable('u_%d' % k,
                                        3,
                                        init=[0, 0, 0],
                                        lb=self.u_min,
                                        ub=self.u_max)
            z_k = self.nlp.new_variable('z_%d' % k,
                                        3,
                                        init=list(contact.p),
                                        lb=z_min,
                                        ub=z_max)
            dT_k = self.nlp.new_variable('dT_%d' % k,
                                         1,
                                         init=[self.dT_init],
                                         lb=[self.dT_min],
                                         ub=[self.dT_max])

            CZ_k = z_k - contact.p
            self.nlp.add_equality_constraint(u_k,
                                             omega2 * (p_k - z_k) + gravity)
            self.nlp.extend_cost(self.weights['zmp'] * casadi.dot(CZ_k, CZ_k) *
                                 dT_k)
            self.nlp.extend_cost(self.weights['acc'] * casadi.dot(u_k, u_k) *
                                 dT_k)

            # Full precision (no Taylor expansion)
            p_next = p_k \
                + v_k / omega * casadi.sinh(omega * dT_k) \
                + u_k / omega2 * (cosh(omega * dT_k) - 1.)
            v_next = v_k * cosh(omega * dT_k) \
                + u_k / omega * sinh(omega * dT_k)
            T_total = T_total + dT_k
            if 2 * k < nb_steps:
                T_swing = T_swing + dT_k

            self.add_com_boundary_constraint(contact, p_k)
            self.add_friction_constraint(contact, p_k, z_k)
            # self.add_friction_constraint(contact, p_next, z_k)
            # self.add_linear_friction_constraints(contact, p_k, z_k)
            # self.add_linear_friction_constraints(contact, p_next, z_k)
            # self.add_cop_constraint(contact, p_k, z_k)
            # self.add_cop_constraint(contact, p_next, z_k)
            self.add_linear_cop_constraints(contact, p_k, z_k)
            # self.add_linear_cop_constraints(contact, p_next, z_k)

            p_k = self.nlp.new_variable('p_%d' % (k + 1),
                                        3,
                                        init=start_com,
                                        lb=self.p_min,
                                        ub=self.p_max)
            v_k = self.nlp.new_variable('v_%d' % (k + 1),
                                        3,
                                        init=start_comd,
                                        lb=self.v_min,
                                        ub=self.v_max)
            self.nlp.add_equality_constraint(p_next, p_k)
            self.nlp.add_equality_constraint(v_next, v_k)

        if swing_duration is not None:
            self.nlp.add_constraint(T_swing,
                                    lb=[swing_duration],
                                    ub=[self.T_max],
                                    name='T_swing')

        p_last, v_last, z_last = p_k, v_k, z_k
        cp_last = p_last + v_last / omega
        cp_last = end_com + end_comd / omega + gravity / omega2
        z_last = z_k
        # last_contact = contact_sequence[-1]
        # self.add_friction_constraint(last_contact, p_last, cp_last)
        # self.add_linear_cop_constraints(last_contact, p_last, cp_last)
        self.nlp.add_equality_constraint(z_last, cp_last)

        p_diff = p_last - end_com
        v_diff = v_last - end_comd
        cp_diff = p_diff + v_diff / omega
        # self.nlp.extend_cost(self.weights['pos'] * casadi.dot(p_diff, p_diff))
        # self.nlp.extend_cost(self.weights['vel'] * casadi.dot(v_diff, v_diff))
        self.nlp.extend_cost(self.weights['cp'] * casadi.dot(cp_diff, cp_diff))
        self.nlp.extend_cost(self.weights['time'] * T_total)
        self.nlp.create_solver()
        #
        self.build_time = time() - t_build_start
        self.contact_sequence = contact_sequence
        self.cp_error = 1e-6  # => self.is_ready_to_switch is initially True
        self.end_com = array(end_com)
        self.end_comd = array(end_comd)
        self.nb_contacts = nb_contacts
        self.nb_steps = nb_steps
        self.omega = omega
        self.omega2 = omega2
        self.p_last = None
        self.preview = ZMPPreviewBuffer(contact_sequence)
        self.state_estimator = state_estimator
        self.swing_dT_min = self.dT_min
        self.swing_duration = swing_duration
        self.v_last = None