User constraints ---------------- .. container:: c-code .. highlight:: c The user constraints enable to impose constraints that can not be resolved using classical Robotran cuts. - The user constraint is expressed in the form: \ :math:`h_{usr}(q) = 0`\ - The user has to provide, for a given configuration: - The value of the constraint: \ :math:`h_{usr}(q)`\ - The Jacobian matrix of the constrain: \ :math:`J_{usr}(q)`\ - The quadratic term: \ :math:`\left(\dot{J}\dot{q}(q, \dot{q})\right)_{usr}`\ - The user constraints are implemented using the *user_cons_hJ* and *user_cons_jdqd* functions. Back to the pendulum-spring example ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The goal is to replace the prismatic joint between the pendulum and the slider by a screw joint. Since only simple joints can be implemented in Robotran, the screw joint will be modelled: - Using a rotoid and a prismatic joint along the same axis; - Adding a constraint to respect the screw thread: - Screw pitch : 20 mm. The constraint can thus be written as: \ :math:`p\varphi - 2\pi z = 0`\ - \ :math:`\varphi`\ : slider rotation along the pendulum; - \ :math:`z`\ : slider translation along the pendulum; - \ :math:`p`\ : the screw pitch Step 1: Draw your multibody system ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Open the Pendulum Spring model in MBsysPad: - Insert a R3 joint in the kinematic chain between the pendulum and the slider - See the `tips and tricks `__ if you don’t know how to modify the attach point of a body. - Give a name to the joint. - Set the R3 joint as dependent .. figure:: figure/userCstr_snapshot_diagramFull.png :alt: A rotation joint is added in the kinematic chain between the pendulum and the slider Illustration of the modified example with the screw joint There is no specific action to do in MBsysPad for the user constraint. Step 2: Generate your multibody equations ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ You have to generate the equations because we added a joint. You also need to regenerate the user models files. However if you add an user constraint on a existing project you don’t have to regenerate the equations because the user constraints are defined in the user functions. Step 3: Write your user function ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. container:: c-code - Edit the *user_cons_hJ* function: - Enter the expression of the constraint: \ :math:`h_{usr}(q)`\ - Fill the jacobian matrix: \ :math:`J_{usr}(q)`\ - Include user_all_id.h. .. code:: c //... #include "user_all_id.h" //... void user_cons_hJ(double *h, double **Jac, MbsData *mbs_data, double tsim) { //... // declare and define pitch value double p = 20e-3; // define the value of the constraint h[1] = p * mbs_data->q[R3_slider_id] -2 * M_PI * mbs_data->q[T3_slider_id]; // define the value of the jacobian matrix Jac[1][T3_slider_id] = -2 * M_PI; Jac[1][R3_slider_id] = p; //... } - Edit the *user_cons_jdqd* function: - No modification to do since the quadratic term of the constraint is null in the present case. - If the quadratic term of the constraint is nonzero you have to define it in this function. Step 4: Run your simulation ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Before running the simulation, you must modify the main script in order to indicate that there is a user constraint. .. container:: c-code Open the main.c file and: - Include mbs_set.h. - add the *mbs_set_nb_usrc* after the program loading and before the partitioning in order to set the number of user constraints: .. code:: c //... #include "mbs_set.h" //... //loading mbs_data // Set the number of user constraints int N_usr_c = 1; mbs_set_nb_userc(mbs_data, N_usr_c); //partitioning // ... In addition, like for loop constraints, the script must call the coordinate partitioning before running the simulation. If it not already there, add the instructions to call the coordinate partitioning module: .. container:: c-code - Open the main.c file and add the following command - After the project loading (*mbs_load()* function) - Before the time integration (*mbs_run_dirdyn()* function) .. code:: c //... // initialisation of structure for the coordinate partitioning mbs_part = mbs_new_part(mbs_data); // options for the coordinate partitioning mbs_part->options->rowperm=1; mbs_part->options->verbose = 1; // compute the coordinate partitioning mbs_run_part(mbs_part, mbs_data); // free the memory mbs_delete_part(mbs_part); //... .. REMARK: Some options are available for the coordinate partitioning process, see the `documentation `__. Check the results ^^^^^^^^^^^^^^^^^ The evolution of the system is the same as for the *External forces* part of the tutorial. This is due to the zero value of the inertia term of the Slider about the rotation axis. So the user constraint do not affect the dynamic of the rest of the system. Set a non-zero value and the rest of the system will be impacted.