Constraints

CTR design optimization framework provides the freedom to the user to add any task-specific constraints. The modular model approach reduces the significant amount of effort to build a customized optimization model. The user can easily build a component in OpenMDAO and add them as constraints in the model. (Note that the kinematics constraints are the necessary constraints that need to remain in the model in order to solve the CTR forward kinematic model).

Kinematics constraints

The code below shows how the kinematics and tube geomerty constraints are added in the optimization.

'''Constraints'''
    bccomp = BcComp(num_nodes=num_nodes,k=k)
    diametercomp = DiameterComp()
    tubeclearancecomp = TubeclearanceComp()
    tubestraightcomp = TubestraightComp()
    baseplanarcomp = BaseplanarComp(num_nodes=num_nodes,k=k,equ_paras=equ_paras)
    deployedlenghtcomp = DeployedlengthComp(k=k)
    betacomp = BetaComp(k=k)

    self.add_subsystem('BetaComp', betacomp, promotes=['*'])
    self.add_subsystem('BcComp', bccomp, promotes=['*'])
    self.add_subsystem('Baseplanarcomp', baseplanarcomp, promotes=['*'])
    self.add_subsystem('DeployedlengthComp', deployedlenghtcomp, promotes=['*'])
    self.add_subsystem('TubestraightComp', tubestraightcomp, promotes=['*'])
    self.add_subsystem('DiameterComp', diametercomp, promotes=['*'])
    self.add_subsystem('TubeclearanceComp', tubeclearancecomp, promotes=['*'])

    # Tube cannot translate inside one another
    self.add_constraint('deployedlength12constraint', lower=1)
    self.add_constraint('deployedlength23constraint', lower=1)
    # keep certain length for the actuation unit to grab the tube
    self.add_constraint('beta12constraint', upper=-5)
    self.add_constraint('beta23constraint', upper=-5)
    # minimum wall thickness
    self.add_constraint('diameterconstraint',lower= 0.1)
    # tube clearance
    self.add_constraint('tubeclearanceconstraint',lower= 0.1,upper=0.16)

Task-specific constraints

Adding OpenMDAO component

An OpenMDAO component needs to be created in order to add a constraint to an optimization. In this example, the user would like to add a constraint on the robot tip orientation.

import numpy as np
from openmdao.api import ExplicitComponent

class TiporientationComp(ExplicitComponent):

    def initialize(self):
        self.options.declare('tube_nbr', default=3, types=int)
        self.options.declare('k', default=3, types=int)
        self.options.declare('num_nodes', default=4, types=int)
        self.options.declare('tar_vector')



    def setup(self):
        num_nodes = self.options['num_nodes']
        k = self.options['k']

        #Inputs
        self.add_input('desptsconstraints',shape=(k,3))

        # outputs
        self.add_output('tiporientation',shape=(k))

        row_indices = np.outer(np.arange(k),np.ones(3)).flatten()
        col_indices = np.arange(k*3)

        self.declare_partials('tiporientation', 'desptsconstraints',rows=row_indices,cols=col_indices)




    def compute(self,inputs,outputs):

        k = self.options['k']
        tar_vector = self.options['tar_vector']
        desptsconstraints = inputs['desptsconstraints']

        dot = (desptsconstraints - tar_vector[:,0]) @  (tar_vector[:,1] - tar_vector[:,0])

        outputs['tiporientation'] = dot


    def compute_partials(self,inputs,partials):
        """ partials Jacobian of partial derivatives."""
        num_nodes = self.options['num_nodes']
        k = self.options['k']
        tar_vector = self.options['tar_vector']

        '''Computing Partials'''
        pd_pp = np.zeros((k,3))
        pd_pp[:,:] = (tar_vector[:,1] - tar_vector[:,0]).T

        partials['tiporientation','desptsconstraints'][:] = pd_pp.flatten()

if __name__ == '__main__':

    from openmdao.api import Problem, Group

    from openmdao.api import IndepVarComp

    group = Group()
    n=1
    k=10
    tar_vector = np.random.rand(3,2)
    comp = IndepVarComp()
    comp.add_output('desptsconstraints', val=np.random.random((k,3)))

    group.add_subsystem('IndepVarComp', comp, promotes = ['*'])


    comp = TiporientationComp(num_nodes=n,k=k,tar_vector=tar_vector)
    group.add_subsystem('desiredpointscomp', comp, promotes = ['*'])

    prob = Problem()
    prob.model = group

    prob.setup()
    prob.run_model()
    prob.model.list_outputs()

    prob.check_partials(compact_print=True)
    # prob.check_partials(compact_print=False)

Adding constraints

Now, the user is able to import and add the output of the component to be the constraints in optimization.

'''Constraints'''
    # kinematics, tube geometry constraints
    bccomp = BcComp(num_nodes=num_nodes,k=k)
    diametercomp = DiameterComp()
    tubeclearancecomp = TubeclearanceComp()
    tubestraightcomp = TubestraightComp()
    baseplanarcomp = BaseplanarComp(num_nodes=num_nodes,k=k,equ_paras=equ_paras)
    deployedlenghtcomp = DeployedlengthComp(k=k)
    betacomp = BetaComp(k=k)
    # declare the Openmdao component for the constraints
    tiporientationcomp = TiporientationComp(k=k,tar_vector=tar_vector)

    self.add_subsystem('BetaComp', betacomp, promotes=['*'])
    self.add_subsystem('BcComp', bccomp, promotes=['*'])
    self.add_subsystem('Baseplanarcomp', baseplanarcomp, promotes=['*'])
    self.add_subsystem('DeployedlengthComp', deployedlenghtcomp, promotes=['*'])
    self.add_subsystem('TubestraightComp', tubestraightcomp, promotes=['*'])
    self.add_subsystem('DiameterComp', diametercomp, promotes=['*'])
    self.add_subsystem('TubeclearanceComp', tubeclearancecomp, promotes=['*'])
    # add the new component into the model
    self.add_subsystem('TiporientationComp', tiporientationcomp, promotes=['*'])



    self.add_constraint('deployedlength12constraint', lower=1)
    self.add_constraint('deployedlength23constraint', lower=1)
    self.add_constraint('beta12constraint', upper=-1)
    self.add_constraint('beta23constraint', upper=-1)
    self.add_constraint('diameterconstraint',lower= 0.1)
    self.add_constraint('tubeclearanceconstraint',lower= 0.1,upper=0.16)
    # add task-specific constraints
    self.add_constraint('tiporientation', equals=0)