All Downloads are FREE. Search and download functionalities are using the official Maven repository.

us.ihmc.simulationconstructionset.Robot Maven / Gradle / Ivy

There is a newer version: 0.25.2
Show newest version
package us.ihmc.simulationconstructionset;

import java.io.PrintStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

import us.ihmc.euclid.matrix.RotationMatrix;
import us.ihmc.euclid.tuple3D.Point3D;
import us.ihmc.euclid.tuple3D.Vector3D;
import us.ihmc.euclid.tuple3D.interfaces.Point3DBasics;
import us.ihmc.euclid.tuple3D.interfaces.Vector3DBasics;
import us.ihmc.euclid.tuple3D.interfaces.Vector3DReadOnly;
import us.ihmc.graphicsDescription.Graphics3DObject;
import us.ihmc.graphicsDescription.yoGraphics.YoGraphicsListRegistry;
import us.ihmc.jMonkeyEngineToolkit.camera.CameraMountInterface;
import us.ihmc.jMonkeyEngineToolkit.camera.CameraMountList;
import us.ihmc.simulationconstructionset.robotdefinition.ExternalForcePointDefinitionFixedFrame;
import us.ihmc.simulationconstructionset.robotdefinition.GroundContactDefinitionFixedFrame;
import us.ihmc.simulationconstructionset.robotdefinition.JointDefinitionFixedFrame;
import us.ihmc.simulationconstructionset.robotdefinition.JointDefinitionFixedFrame.JointType;
import us.ihmc.simulationconstructionset.robotdefinition.RobotDefinitionFixedFrame;
import us.ihmc.simulationconstructionset.simulatedSensors.LidarMount;
import us.ihmc.simulationconstructionset.simulatedSensors.WrenchCalculatorInterface;
import us.ihmc.simulationconstructionset.util.RobotController;
import us.ihmc.yoVariables.registry.YoNamespace;
import us.ihmc.yoVariables.registry.YoRegistry;
import us.ihmc.yoVariables.registry.YoVariableHolder;
import us.ihmc.yoVariables.registry.YoVariableList;
import us.ihmc.yoVariables.variable.YoDouble;
import us.ihmc.yoVariables.variable.YoVariable;

/**
 * 

* Title: Robot *

*

* Description: A Robot is a forest of trees of Joints, each Joint having an associated Link. The * Robot contains all the dynamic information, including Joint types, offsets between Joints, Link * masses, center of mass locations, and moments of inertia. Each root joint has children *

* * @author Jerry Pratt * @version 1.0 */ public class Robot implements YoVariableHolder, GroundContactPointsHolder { protected YoRegistry yoRegistry; protected final List yoGraphicsListRegistries = new ArrayList<>(); private List rootJoints; private FunctionIntegrators functionIntegrators = null; private final String name; protected YoDouble t; // The gravitational constants for each axis public YoDouble gravityX; public YoDouble gravityY; public YoDouble gravityZ; // protected double gX = 0.0, gY = 0.0, gZ = -9.81; private List controllers = new ArrayList<>(); private GroundContactModel groundContactModel; private ExternalForcePoint kp_body; private DynamicIntegrationMethod dynamicIntegrationMethod = DynamicIntegrationMethod.RUNGE_KUTTA_FOURTH_ORDER; private final List staticLinkGraphics = new ArrayList<>(); // private VarList robVars; // private VarList groundVars; // private List controllerVarLists = new ArrayList(); public Robot(RobotDefinitionFixedFrame definition, String name) { this(name); constructRobotFromDefinition(definition); } private void constructRobotFromDefinition(RobotDefinitionFixedFrame definition) { for (JointDefinitionFixedFrame currentRootJoint : definition.getRootJointDefinitions()) { traverseJointDefinitions(currentRootJoint, null); } } private void traverseJointDefinitions(JointDefinitionFixedFrame jointDefinition, Joint parent) { Joint currentJoint = null; if (jointDefinition.getType() == JointType.FLOATING_JOINT) { currentJoint = new FloatingJoint(jointDefinition.getJointName(), jointDefinition.getOffset(), this); } else if (jointDefinition.getType() == JointType.FLOATING_PLANAR_JOINT) { currentJoint = new FloatingPlanarJoint(jointDefinition.getJointName(), this, jointDefinition.getPlanarType()); } else if (jointDefinition.getType() == JointType.PIN_JOINT) { currentJoint = new PinJoint(jointDefinition.getJointName(), jointDefinition.getOffset(), this, jointDefinition.getJointAxis()); } else if (jointDefinition.getType() == JointType.SLIDER_JOINT) { currentJoint = new SliderJoint(jointDefinition.getJointName(), jointDefinition.getOffset(), this, jointDefinition.getJointAxis()); } for (GroundContactDefinitionFixedFrame groundContactDefinitionFixedFrame : jointDefinition.getGroundContactDefinitionsFixedFrame()) { GroundContactPoint groundContactPoint = new GroundContactPoint(groundContactDefinitionFixedFrame.getName(), groundContactDefinitionFixedFrame.getOffset(), getRobotsYoRegistry()); currentJoint.addGroundContactPoint(groundContactPoint); } for (ExternalForcePointDefinitionFixedFrame externalForcePointDefinitionFixedFrame : jointDefinition.getExternalForcePointDefinitionsFixedFrame()) { ExternalForcePoint externalForcePoint = new ExternalForcePoint(externalForcePointDefinitionFixedFrame.getName(), externalForcePointDefinitionFixedFrame.getOffset(), getRobotsYoRegistry()); currentJoint.addExternalForcePoint(externalForcePoint); } currentJoint.setLink(new Link(jointDefinition.getLinkDefinition())); if (parent == null) addRootJoint(currentJoint); else parent.addJoint(currentJoint); for (JointDefinitionFixedFrame childJoint : jointDefinition.getChildrenJoints()) { traverseJointDefinitions(childJoint, currentJoint); } } /** * Creates a Robot with the specified name. A Robot is a forest of trees of Joints, each Joint * having an associated Link. * * @param name Name of the robot. */ public Robot(String name) { this.name = name; yoRegistry = new YoRegistry(name); rootJoints = new ArrayList<>(); t = new YoDouble("t", yoRegistry); gravityX = new YoDouble("gravityX", yoRegistry); gravityY = new YoDouble("gravityY", yoRegistry); gravityZ = new YoDouble("gravityZ", yoRegistry); setDefaultGravityToEarthWithMetricUnits(); } public void setDynamicIntegrationMethod(DynamicIntegrationMethod dynamicIntegrationMethod) { this.dynamicIntegrationMethod = dynamicIntegrationMethod; } private void setDefaultGravityToEarthWithMetricUnits() { gravityZ.set(-9.81); } /** * Gets this robot's time. * * @return double */ public double getTime() { return t.getDoubleValue(); } /** * Sets this robot's time. */ public void setTime(double time) { t.set(time); } public void setDynamic(boolean isDynamic) { for (Joint joint : rootJoints) { joint.setDynamic(isDynamic); } } /** * Gets this robot's time * * @return YoVariable */ public YoDouble getYoTime() { return t; } /** * Gets this robot's component of gravitational acceleration in the x-direction. * * @return double */ public double getGravityX() { return gravityX.getDoubleValue(); } /** * Gets this robot's component of gravitational acceleration in the y-direction. * * @return double */ public double getGravityY() { return gravityY.getDoubleValue(); } /** * Gets this robot's component of gravitational acceleration in the z-direction. * * @return double */ public double getGravityZ() { return gravityZ.getDoubleValue(); } public void getGravity(Vector3D gravityVectorToPack) { gravityVectorToPack.set(gravityX.getDoubleValue(), gravityY.getDoubleValue(), gravityZ.getDoubleValue()); } /** * Adds a YoRegistry to the robot. Will be added as a child registry to the robot's registry. * * @param registry YoRegistry */ public void addYoRegistry(YoRegistry registry) { if (registry == null) throw new RuntimeException("Cannot add a null registry to " + name + "!!!!"); getRobotsYoRegistry().addChild(registry); } public void addYoGraphicsListRegistry(YoGraphicsListRegistry yoGraphicsListRegistry) { if (yoGraphicsListRegistry == null) { throw new RuntimeException("Cannot add a null yoGraphicsListRegistry to " + name + "!!!!"); } yoGraphicsListRegistries.add(yoGraphicsListRegistry); } /** * Adds a root Joint to this robot. This joint may have multiple child joints which also can have * children. A robot may have any number of root joints. * * @param root Joint to be added as the root Joint. A robot is comprised of a forest of trees, with * one root Joint per tree. */ public void addRootJoint(Joint root) { rootJoints.add(root); } /** * Retrieves this robot's ground contact model. * * @return GroundContactModel The GroundContactModel of this robot. * @see GroundContactModel GroundContactModel */ public GroundContactModel getGroundContactModel() { return groundContactModel; } /** * Step through each joint to determine if any points are in contact with the ground. */ public void decideGroundContactPointsInContact() { List children = this.getRootJoints(); for (int i = 0; i < children.size(); i++) { Joint rootJoint = children.get(i); rootJoint.physics.recursiveDecideGroundContactPointsInContact(); } } public void doLoopClosure() { List children = this.getRootJoints(); for (int i = 0; i < children.size(); i++) { Joint rootJoint = children.get(i); rootJoint.physics.doLoopClosureRecursive(); } } /** * Retrieves an List containing the rootJoints of this robot. These joints make up the entirety of * the robot's visual component as all joints and links are at some level their children. * * @return List containing the root joints of the robot. */ public List getRootJoints() { return rootJoints; } public void getRootJoints(List jointsToPack) { jointsToPack.addAll(rootJoints); } /** * Sets gravity to the specified values. For example, if using meter-kilogram-seconds units of * measure with Earth's gravity, then use setGravity(0.0, 0.0, -9.81); * * @param gravityX X component of the Gravity vector. * @param gravityY Y component of the Gravity vector. * @param gravityZ Z component of the Gravity vector. */ public void setGravity(double gravityX, double gravityY, double gravityZ) { this.gravityX.set(gravityX); this.gravityY.set(gravityY); this.gravityZ.set(gravityZ); } public void setGravity(Vector3DReadOnly gravity) { gravityX.set(gravity.getX()); gravityY.set(gravity.getY()); gravityZ.set(gravity.getZ()); } /** * Sets the Z component of the gravity to the specified value. For example, if using * meter-kilogram-seconds units of measure with Earth's gravity, then use setGravity(-9.81); * * @param gZ Z component of the Gravity vector. X and Y components are set to 0.0. */ public void setGravity(double gZ) { setGravity(0.0, 0.0, gZ); } /** * Adds a FunctionToIntegrate which will be integrated each simulation step. If no functions are * present that step is skipped. * * @param functionToIntegrate The function to be integrated. * @see FunctionToIntegrate FunctionToIntegrate */ public void addFunctionToIntegrate(FunctionToIntegrate functionToIntegrate) { if (functionToIntegrate == null) return; if (functionIntegrators == null) functionIntegrators = new FunctionIntegrators(); functionIntegrators.addFunctionIntegrator(new FunctionIntegrator(functionToIntegrate)); // functionIntegrator = new FunctionIntegrator(functionToIntegrate); } //TODO: Refactor all setController methods to addController /** * Adds a controller to use with this Robot. A single robot can have multiple controllers, all of * which execute their {@link RobotController#doControl doControl} methods when called. Controllers * added with this function doControl every simulation tick. * * @param controller RobotController to use with this robot. * @see RobotController RobotController */ public void setController(RobotController controller) { setController(controller, 1); } /** * Adds a controller to use with this Robot. This method provides a method for reducing the number * of control ticks per simulation tick. In other words, the controller only executes once every x * simulation ticks. * * @param controller RobotController to use with this robot. * @param simulationTicksPerControlTick Number of simulation ticks per control tick. */ public void setController(RobotController controller, int simulationTicksPerControlTick) { setController(new RobotControllerAndParameters(controller, simulationTicksPerControlTick)); } public void setController(List controllers, int simulationTicksPerControlTick) { for (int i = 0; i < controllers.size(); i++) { RobotController controller = controllers.get(i); setController(controller, simulationTicksPerControlTick); } } public void setControllersAndCallInitialization(List robotControllersAndParameters) { for (RobotControllerAndParameters robotControllerAndParameters : robotControllersAndParameters) { setController(robotControllerAndParameters); robotControllerAndParameters.getController().initialize(); } } public void setController(RobotControllerAndParameters controllerAndParameters) { YoRegistry registry = controllerAndParameters.getController().getYoRegistry(); controllers.add(controllerAndParameters); addYoRegistry(registry); } /** * Executes the doControl method for each controller assigned to this robot. This method is called * once per simulation tick. If simulationTicksPerControlTick for a given controller is something * other than one the function will skip that controller. */ public final void doControllers() { if (controllers == null) return; // for(RobotControllerAndParameters controller : controllers) for (int i = 0; i < controllers.size(); i++) { RobotControllerAndParameters controller = controllers.get(i); controller.ticks_till_control.set(controller.ticks_till_control.getIntegerValue() - 1); if (controller.ticks_till_control.getIntegerValue() <= 0) { controller.ticks_till_control.set(controller.simulationTicksPerControlTick); controller.controller.doControl(); } } } // public RobotController getController(){return this.controller;} /** * Sets the ground contact model for this robot. This allow the robot to interact with its * surroundings based on their characteristics. * * @param gcModel GroundContactModel to be used with this robot. * @see GroundContactModel GroundContactModel */ public void setGroundContactModel(GroundContactModel gcModel) { groundContactModel = gcModel; } /** * Retrieves the VarList associated with this robot's GroundContactModel. Will return null if a * model was not added. * * @return VarList associated with the GroundContactModel */ // protected VarList getGroundContactVarList(){return this.groundVars;} // protected List getControllerVarLists(){return this.controllerVarLists;} // protected VarList getExternalForceVarList(){return this.groundVars;} /** * Gets the name of this Robot. * * @return Name of this Robot. */ public String getName() { return name; } /** * Returns a list of the YoVariables associated with this robot. This list does not include * variables belonging to its GroundContactModel or controllers. * * @return VarList of the Robot's variables. */ public void update() { boolean updatePoints = true; boolean updateCameraMounts = true; boolean updateIMUMounts = true; update(updatePoints, updateCameraMounts, updateIMUMounts); } public void updateForPlayback() { boolean updatePoints = false; boolean updateCameraMounts = true; boolean updateIMUMounts = false; update(updatePoints, updateCameraMounts, updateIMUMounts); } /** * Updates all joint data without updating graphics. TODO: Not sure if this needs to be synchronized * anymore. */ protected synchronized void update(boolean updatePoints, boolean updateCameraMounts, boolean updateIMUMounts) { for (int i = 0; i < rootJoints.size(); i++) { Joint rootJoint = rootJoints.get(i); rootJoint.recursiveUpdateJoints(null, updatePoints, updateCameraMounts, updateIMUMounts, t.getDoubleValue()); } } public void updateIMUMountAccelerations() { for (int i = 0; i < rootJoints.size(); i++) { Joint rootJoint = rootJoints.get(i); rootJoint.recursiveUpdateJointsIMUMountAccelerations(); } } /** * Updates the velocities for all ground contact points. This is called once per simulation tick to * ensure all ground contact point velocities are updated. */ public void updateAllGroundContactPointVelocities() { for (int i = 0; i < rootJoints.size(); i++) { Joint rootJoint = rootJoints.get(i); // +++JEP: OPTIMIZE rootJoint.physics.recursiveUpdateAllGroundContactPointVelocities(); } } private Vector3D w_null = new Vector3D(); private Vector3D v_null = new Vector3D(); private SpatialVector a_hat_h_null = new SpatialVector(); private RotationMatrix R_0_i = new RotationMatrix(); /** * Steps through every joint adding each camera mount to the provided list. This function is called * by the GUI on one of two occasions. When the GUI is created and when a robot is set. In both * cases the method is not called in the null robot case. * * @param cameraMountList CameraMountList to which all mount points are added. */ public void getCameraMountList(CameraMountList cameraMountList) { List mountArrayList = new ArrayList<>(); List children = this.getRootJoints(); for (int i = 0; i < children.size(); i++) { Joint rootJoint = children.get(i); rootJoint.recursiveGetCameraMounts(mountArrayList); cameraMountList.addCameraMounts(mountArrayList); } } public List getSensors() { List ret = new ArrayList<>(); List children = this.getRootJoints(); for (int i = 0; i < children.size(); i++) { Joint rootJoint = children.get(i); rootJoint.recursiveGetSensors(ret); } return ret; } /** * Returns an List appropriate to the type of sensor being queried containing all the sensors of * that type for each joint. */ @SuppressWarnings("unchecked") public List getSensors(Class sensorType) { List allSensors = getSensors(); List specificSensors = new ArrayList<>(); for (SimulatedSensor sensor : allSensors) { if (sensorType.isAssignableFrom(sensor.getClass())) { specificSensors.add((T) sensor); } } return specificSensors; } public void getAllOneDegreeOfFreedomJoints(List oneDegreeOfFreedomJoints) { List children = this.getRootJoints(); for (int i = 0; i < children.size(); i++) { Joint rootJoint = children.get(i); rootJoint.recursiveGetOneDegreeOfFreedomJoints(oneDegreeOfFreedomJoints); } } public void getAllLoopClosureSoftConstraints(List constraintsToPack) { List children = this.getRootJoints(); for (int i = 0; i < children.size(); i++) { Joint rootJoint = children.get(i); rootJoint.recursiveGetChildrenConstraints(constraintsToPack); } } public void getLidarMounts(List lidarMountsToPack) { List children = this.getRootJoints(); for (int i = 0; i < children.size(); i++) { Joint rootJoint = children.get(i); rootJoint.recursiveGetLidarMounts(lidarMountsToPack); } } public void getIMUMounts(List imuMountsToPack) { List children = this.getRootJoints(); for (int i = 0; i < children.size(); i++) { Joint rootJoint = children.get(i); rootJoint.recursiveGetIMUMounts(imuMountsToPack); } } public void getForceSensors(List forceSensors) { List children = this.getRootJoints(); for (int i = 0; i < children.size(); i++) { Joint rootJoint = children.get(i); rootJoint.recursiveGetForceSensors(forceSensors); } } /** * Retrieves a list of all ground contact points associated with this robot and the * groundContactGroupIdentifier. * * @return List containing the GroundContactPoints, if none exist the list will be empty. */ @Override public List getGroundContactPoints(int groundContactGroupIdentifier) { List ret = new ArrayList<>(); List children = this.getRootJoints(); for (int i = 0; i < children.size(); i++) { Joint rootJoint = children.get(i); rootJoint.physics.recursiveGetGroundContactPoints(groundContactGroupIdentifier, ret); } return ret; } public List> getAllGroundContactPointsGroupedByJoint() { List> ret = new ArrayList<>(); List children = this.getRootJoints(); for (int i = 0; i < children.size(); i++) { Joint rootJoint = children.get(i); rootJoint.physics.recursiveGetAllGroundContactPointsGroupedByJoint(ret); } return ret; } public List getAllGroundContactPoints() { List ret = new ArrayList<>(); List children = this.getRootJoints(); for (int i = 0; i < children.size(); i++) { Joint rootJoint = children.get(i); rootJoint.physics.recursiveGetAllGroundContactPoints(ret); } return ret; } public List getAllExternalForcePoints() { List ret = new ArrayList<>(); List children = this.getRootJoints(); for (int i = 0; i < children.size(); i++) { Joint rootJoint = children.get(i); rootJoint.physics.recursiveGetAllExternalForcePoints(ret); } return ret; } public List getAllKinematicPoints() { List ret = new ArrayList<>(); List children = this.getRootJoints(); for (int i = 0; i < children.size(); i++) { Joint rootJoint = children.get(i); rootJoint.physics.recursiveGetAllKinematicPoints(ret); } return ret; } public ExternalForcePoint getExternalForcePoint(String name) { List children = this.getRootJoints(); for (int i = 0; i < children.size(); i++) { Joint rootJoint = children.get(i); ExternalForcePoint externalForcePoint = rootJoint.recursiveGetExternalForcePoint(name); if (externalForcePoint != null) return externalForcePoint; } return null; } /** * Adds the specified link to the robot. Static links have no effect on the simulation, they are * purely cosmetic. * * @param staticLink Link to be added. */ public void addStaticLink(Link staticLink) { addStaticLinkGraphics(staticLink.getLinkGraphics()); } /** * Adds the specified LinkGraphics to the robot. Static LinkGraphics have no effect on the * simulation, they are purely cosmetic. * * @param linkGraphics LinkGraphics to be added. */ public void addStaticLinkGraphics(Graphics3DObject linkGraphics) { staticLinkGraphics.add(linkGraphics); } public void addStaticLinkGraphics(List linkGraphicsArray) { for (Graphics3DObject linkGraphics : linkGraphicsArray) { addStaticLinkGraphics(linkGraphics); } } /** * Updates the velocities and positions at each joint as well as the rotation matrices from and to * the base coordinate system. Each joint stores both its rotational and translational velocities. * The updated velocities are based on those of the previous joint in the chain. This also updates * all kinetic and ground contact points. */ public void updateVelocities() { List children = this.getRootJoints(); for (int i = 0; i < children.size(); i++) { Joint rootJoint = children.get(i); R_0_i.setIdentity(); w_null.set(0.0, 0.0, 0.0); v_null.set(0.0, 0.0, 0.0); a_hat_h_null.top.set(0.0, 0.0, 0.0); a_hat_h_null.bottom.set(0.0, 0.0, 0.0); rootJoint.physics.featherstonePassOne(w_null, v_null, R_0_i); } this.update(); } /** * This function handles the dynamics of the robot. While simulating, each simulation "tick" * triggers this function four times allowing the calculation of the four Runge-Kutta coefficients. * These coefficients are calculated by executing the four Featherstone passes on each joint tree. * The first pass recurses down the tree, calculating the linear and angular velocities for each * link. In the process the rotation matrices and radius vectors are recalculated. The coordinate * system of each joint/link space is centered on the current link's center of mass. Each joint * contains a rotation matrix and corresponding radius vector to translate information to and from * the previous link's coordinate system. These functions must be updated before the velocities may * be calculated. The kinematic and ground contact points for each joint are also updated. Pass two * recurses down the tree again, calculating the isolated components of the spatial articulated * inertia and spatial isolated zero-acceleration force for each link. Coriolis forces and forces * from ground contact and kinetic points are included in these calculations. In the third pass the * completed articulated inertia and articulated z.a. forces are calculated for each link by * recursing up the tree. These values are based on the positions, velocities and torques of each * link. The final pass recurses down the tree calculating the joint accelerations based on the * information generated by the previous three passes. During this pass the joint positions, * velocities and accelerations are stored for use in the Runge-Kutta calculations. * * @param passNumber Current pass, this is used in featherstonePassFour when saving the current * values of k_q, k_qd, and k_qdd * @throws UnreasonableAccelerationException */ private void doDynamics(int passNumber) throws UnreasonableAccelerationException { List children = this.getRootJoints(); for (int i = 0; i < children.size(); i++) { Joint rootJoint = children.get(i); if (rootJoint.isDynamic()) { R_0_i.setIdentity(); w_null.set(0.0, 0.0, 0.0); v_null.set(0.0, 0.0, 0.0); a_hat_h_null.top.set(0.0, 0.0, 0.0); a_hat_h_null.bottom.set(0.0, 0.0, 0.0); rootJoint.physics.featherstonePassOne(w_null, v_null, R_0_i); // System.out.println("\n\n"); rootJoint.physics.featherstonePassTwo(w_null); rootJoint.physics.featherstonePassThree(); rootJoint.physics.featherstonePassFour(a_hat_h_null, passNumber); } else { R_0_i.setIdentity(); w_null.set(0.0, 0.0, 0.0); v_null.set(0.0, 0.0, 0.0); a_hat_h_null.top.set(0.0, 0.0, 0.0); a_hat_h_null.bottom.set(0.0, 0.0, 0.0); rootJoint.physics.featherstonePassOne(w_null, v_null, R_0_i); // rootJoint.featherstonePassTwo(w_null); // rootJoint.featherstonePassThree(); // rootJoint.featherstonePassFour(a_hat_h_null, passNumber); rootJoint.physics.recordK(passNumber); } } } public YoRegistry getRobotsYoRegistry() { return yoRegistry; } public void setRobotsYoRegistry(YoRegistry registry) { yoRegistry = registry; } /** * Saves the current state of each joint. Different joint types have different relevant values, pin * and slider joints store only position and velocity. These values are restored prior to each Euler * integration in order to properly calculate the Runge-Kutta slope. */ private void rootJointsRecursiveSaveTempState() { List children = this.getRootJoints(); for (int i = 0; i < children.size(); i++) { Joint rootJoint = children.get(i); rootJoint.physics.recursiveSaveTempState(); } } /** * Calculates the position and velocity for each joint using euler integration. y_(n+1) = y_n + * h*f(t_n, y_n) where h is the step size. This function used in the calculation of the Runge-Kutta * slope. * * @param dt Time step size for Euler integration */ public void rootJointsRecursiveEulerIntegrate(double dt) { List children = this.getRootJoints(); for (int i = 0; i < children.size(); i++) { Joint rootJoint = children.get(i); rootJoint.physics.recursiveEulerIntegrate(dt); } } /** * Steps through evey joint restoring the saved values for use in the next Euler integration. */ private void rootJointsRecursiveRestoreTempState() { List children = this.getRootJoints(); for (int i = 0; i < children.size(); i++) { Joint rootJoint = children.get(i); rootJoint.physics.recursiveRestoreTempState(); } } /** * Steps through each joint updating data using the Runge-Kutta method The next value in a * Runge-Kutta series is described by the following formulas: y_(n+1) = y_n + (1/6) * h * (k_1 + * 2k_2 + 2 k_3 + k_4) t_(n+1) = t_n + h Where: h is the step size (dt) k_1 is the slope at the * beginning of the interval k_2 is the slope at the midpoint of the interval calcuated by using k_1 * to predict the value of y at point t_n + h/2 using Euler's method k_3 is the slope at the * midpoint recalculated using k_2 k_4 is the slope at the end of the interval determined via k_3 * These coefficents are calculated by the doDynamics function and stored. That function is called * four times, once per k after a Euler integration steps the values. * * @param dt Step size to be used. */ private void rootJointsRecursiveRungeKuttaSum(double dt) { List children = this.getRootJoints(); for (int i = 0; i < children.size(); i++) { Joint rootJoint = children.get(i); rootJoint.physics.recursiveRungeKuttaSum(dt); } } // Override this method if you wish to do something before the dynamics tick, // For example, simulate a spring. This will get called only once per tick, even though the Runge-Kutta // integrator will do the dynamics 4 times per tick. public void doAfterControlBeforeDynamics() { } /** * Will update the qdd values of the joints, but not integrate the velocities or anything like that. * Good for testing inverse dynamics routines and things like that. */ public void doDynamicsButDoNotIntegrate() throws UnreasonableAccelerationException { doAfterControlBeforeDynamics(); doDynamics(0); } /** *

* Calculates the robot dynamics and integrates to the next step. This integration is accomplished * via the Runge-Kutta method which approximates the next point in the series by calculating four * intermediary slopes. The robot dynamics are calculated four times using the following method to * generate these Runge-Kutta slopes. *

*

* Robot dynamics are calculated via the Featherstone algorithm as discussed by Brian Mirtich in his * Thesis, Impule-based Dynamic Simulation of Rigid Body Systems. This algorithm is * implemented in four distinct passes as follows: *

*
    *
  1. The first pass recurses down the tree, calculating the linear and angular velocities for each * link. In the process the rotation matricies and radius vectors are recalculated. The coordinate * system of each joint/link space is centered on the current link's center of mass. Each joint * contains a rotation matrix and corresponding radius vector to translate information to and from * the previous link's coordinate system. These functions must be updated before the velocities may * be calculated. The kinematic and ground contact points as well as torque for each joint are also * updated.
  2. *
  3. Pass two recurses down the tree again, calculating the isolated components of the spatial * articulated inertia and spatial isolated zero-acceleration force for each link. Coriolis forces * and forces from ground contact and kinetic points are included in these calculations.
  4. *
  5. In the third pass the completed articulated inertia and articulated z.a. forces are * calculated for each link by recursing up the tree. These values are based on the positions, * velocities and torques of each link.
  6. *
  7. The final pass recurses down the tree calculating the joint accelerations based on the * information generated by the previous three passes. During this pass the joint positions, * velocities and accelerations are stored for use in the Runge-Kutta calculations.
  8. *
*

* Between each run of the dynamics Euler Integration is used to shift the values in preparation for * the next step. However, the values are returned to their original states before each integration. * Each pass of the dynamics stores the Runge-Kutta slope for each parameter. Once the dynamics have * been calculated the joints are checked for unreasonable accelerations. If none are present, * Runge-Kutta is executed for each joint and the current time is updated. * * @param DT Step time for the integration. * @throws UnreasonableAccelerationException This exception indicates that at least one joint * underwent an unreasonable acceleration as defined by * its joint type. This is often caused by overly large * step times (DT). */ public void doDynamicsAndIntegrate(double DT) throws UnreasonableAccelerationException { doAfterControlBeforeDynamics(); if (functionIntegrators != null) { doDynamicsAndIntegrateWithFunction(DT); return; } double temp_time = t.getDoubleValue(); switch (dynamicIntegrationMethod) { case RUNGE_KUTTA_FOURTH_ORDER: { rootJointsRecursiveSaveTempState(); doDynamics(0); rootJointsRecursiveEulerIntegrate(DT / 2.0); doDynamics(1); rootJointsRecursiveRestoreTempState(); rootJointsRecursiveEulerIntegrate(DT / 2.0); doDynamics(2); rootJointsRecursiveRestoreTempState(); rootJointsRecursiveEulerIntegrate(DT); doDynamics(3); rootJointsRecursiveRungeKuttaSum(DT); t.set(temp_time + DT); break; } case EULER_DOUBLE_STEPS: { rootJointsRecursiveSaveTempState(); doDynamics(0); rootJointsRecursiveEulerIntegrate(DT / 2.0); t.set(temp_time + DT / 2.0); rootJointsRecursiveSaveTempState(); doDynamics(1); rootJointsRecursiveEulerIntegrate(DT / 2.0); t.set(temp_time + DT); break; } default: throw new RuntimeException("Should not get here"); } // } // else // { // List unreasonableAccelerationJoints = getUnreasonableAccelerationJoints(); // throw new UnreasonableAccelerationException(unreasonableAccelerationJoints); // // // System.err.println("Unreasonable Accelerations!"); // } } private void doDynamicsAndIntegrateWithFunction(double DT) throws UnreasonableAccelerationException { double temp_time = t.getDoubleValue(); // Save the temporary state functionIntegrators.saveTempState(); rootJointsRecursiveSaveTempState(); update(); functionIntegrators.doDynamics(0); doDynamics(0); functionIntegrators.eulerIntegrate(DT / 2.0); rootJointsRecursiveEulerIntegrate(DT / 2.0); update(); t.set(temp_time + DT / 2.0); functionIntegrators.doDynamics(1); doDynamics(1); functionIntegrators.restoreTempState(); rootJointsRecursiveRestoreTempState(); functionIntegrators.eulerIntegrate(DT / 2.0); rootJointsRecursiveEulerIntegrate(DT / 2.0); update(); functionIntegrators.doDynamics(2); doDynamics(2); functionIntegrators.restoreTempState(); rootJointsRecursiveRestoreTempState(); functionIntegrators.eulerIntegrate(DT); rootJointsRecursiveEulerIntegrate(DT); update(); t.set(temp_time + DT); functionIntegrators.doDynamics(3); doDynamics(3); functionIntegrators.rungeKuttaSum(DT); rootJointsRecursiveRungeKuttaSum(DT); // Increase time t.set(temp_time + DT); } /** * Computes the total translational kinetic energy of this Robot. This is the sum over i of 1/2 m_i * v_i*v_i, where m_i is the mass of link i, and v_i is the translational velocity of the center of * mass of link i. * * @return Total translational kinetic energy. */ public double computeTranslationalKineticEnergy() { double translationalKineticEnergy = 0.0; for (int i = 0; i < rootJoints.size(); i++) { Joint rootJoint = rootJoints.get(i); translationalKineticEnergy = translationalKineticEnergy + computeTranslationalKineticEnergy(rootJoint); } return translationalKineticEnergy; } /** * Computes the total translational kinetic energy of the subtree rooted at the specified root * Joint. This is the sum over i of 1/2 m_i v_i*v_i, where m_i is the mass of link i, and v_i is the * translational velocity of the center of mass of link i, and i includes all decendents of the * specified root Joint. * * @return Total translational kinetic energy of the subtree rooted at the specified root Joint. * @param rootJoint Root Joint to compute energy from. */ public double computeTranslationalKineticEnergy(Joint rootJoint) { return rootJoint.physics.recursiveComputeTranslationalKineticEnergy(); } /** * Computes the total rotational kinetic energy of this Robot. This is the sum over i of 1/2 * w_i^T*J_i*w_i, where J_i is the ineria matrix of link i, and w_i is the rotational velocity * vector of the center of mass of link i. * * @return Total rotational kinetic energy. */ public double computeRotationalKineticEnergy() { double rotationalKineticEnergy = 0.0; for (int i = 0; i < rootJoints.size(); i++) { Joint rootJoint = rootJoints.get(i); rotationalKineticEnergy = rotationalKineticEnergy + computeRotationalKineticEnergy(rootJoint); } return rotationalKineticEnergy; } /** * Computes the total rotational kinetic energy of the subtree rooted at the specified root Joint. * This is the sum over i of 1/2 w_i^T*J_i*w_i, where J_i is the inertia matrix of link i, and w_i * is the rotational velocity vector of the center of mass of link i, and i consisting of all the * decendents of the specified root Joint. * * @return Total rotational kinetic energy of the subtree rooted at the specified root Joint. * @param rootJoint Root Joint to compute energy from. */ public double computeRotationalKineticEnergy(Joint rootJoint) { return rootJoint.physics.recursiveComputeRotationalKineticEnergy(); } /** * Computes the total gravitational potential energy of this Robot. This is the sum over i of * m_i*g*h_i, where m_i is the mass of link i, g is the gravitational constant, and h_i is the * height above 0 of link i. * * @return Total gravitational potential energy. */ public double computeGravitationalPotentialEnergy() { double gravitationalPotentialEnergy = 0.0; for (int i = 0; i < rootJoints.size(); i++) { Joint rootJoint = rootJoints.get(i); gravitationalPotentialEnergy = gravitationalPotentialEnergy + computeGravitationalPotentialEnergy(rootJoint); } return gravitationalPotentialEnergy; } /** * Computes the total gravitational potential energy of the subtree rooted at the specified root * Joint. This is the sum over i of m_i*g*h_i, where m_i is the mass of link i, g is the * gravitational constant, and h_i is the height above 0 of link i, with i consisting of all the * decendents of the specified root Joint. * * @return Total gravitational potential energy. */ public double computeGravitationalPotentialEnergy(Joint rootJoint) { return rootJoint.physics.recursiveComputeGravitationalPotentialEnergy(); } private Point3D tempCOMPoint = new Point3D(); // Temporary point storing the robot's center of mass /** * Computes the center of mass of this Robot. This center of mass position is returned by altering * the provided Point3D. If the robot has no mass, it also has no center of mass point. This value * is used in the calculation of center of momentum. * * @param comPoint Center of Mass point, in World Coordinates, that is computed. * @return The total mass of the robot. */ public double computeCenterOfMass(Point3DBasics comPoint) { double totalMass = 0.0; comPoint.set(0.0, 0.0, 0.0); for (int i = 0; i < rootJoints.size(); i++) { Joint rootJoint = rootJoints.get(i); double mass = rootJoint.physics.recursiveComputeCenterOfMass(tempCOMPoint); totalMass = totalMass + mass; tempCOMPoint.scale(mass); comPoint.add(tempCOMPoint); } if (totalMass > 0.0) { comPoint.scale(1.0 / totalMass); } else comPoint.set(0.0, 0.0, 0.0); return totalMass; } /** * Computes the Center of Mass of the subtree rooted at the specified root Joint. This center of * mass position is returned by altering the provided Point3D. If the robot has no mass, it also has * no center of mass point. * * @param comPoint Center of Mass point, in World Coordinates, that is computed. * @return The total mass of the robot. */ public double computeCenterOfMass(Joint rootJoint, Point3DBasics comPoint) { double totalMass = 0.0; comPoint.set(0.0, 0.0, 0.0); double mass = rootJoint.physics.recursiveComputeCenterOfMass(tempCOMPoint); totalMass = totalMass + mass; tempCOMPoint.scale(mass); comPoint.add(tempCOMPoint); if (totalMass > 0.0) { comPoint.scale(1.0 / totalMass); } else comPoint.set(0.0, 0.0, 0.0); return totalMass; } private Vector3D tempLinearMomentum = new Vector3D(); /** * Computes the total linear momentum of the center of mass for this Robot. The total mass of the * robot is also computed and returned. * * @param linearMomentum Total linear momentum vector that is computed. * @return The total mass of the robot. */ public double computeLinearMomentum(Vector3DBasics linearMomentum) { double totalMass = 0.0; linearMomentum.set(0.0, 0.0, 0.0); for (int i = 0; i < rootJoints.size(); i++) { Joint rootJoint = rootJoints.get(i); double mass = rootJoint.physics.recursiveComputeLinearMomentum(tempLinearMomentum); totalMass = totalMass + mass; linearMomentum.add(tempLinearMomentum); } return totalMass; } /** * Computes the total linear momentum of the center of mass for the subtree rooted at the specified * root Joint. The total mass of the robot is also computed and returned. * * @param rootJoint Root Joint for which linear momentum is computed. * @param linearMomentum Total linear momentum vector that is computed. * @return The total mass of the robot. */ public double computeLinearMomentum(Joint rootJoint, Vector3DBasics linearMomentum) { double totalMass = 0.0; linearMomentum.set(0.0, 0.0, 0.0); double mass = rootJoint.physics.recursiveComputeLinearMomentum(tempLinearMomentum); totalMass = totalMass + mass; linearMomentum.add(tempLinearMomentum); return totalMass; } private Vector3D tempAngularMomentum = new Vector3D(); /** * Computes the total angular momentum about the center of mass for this Robot. * * @param angularMomentum Total angular momentum vector that is computed. */ public void computeAngularMomentum(Vector3DBasics angularMomentum) { angularMomentum.set(0.0, 0.0, 0.0); for (int i = 0; i < rootJoints.size(); i++) { Joint rootJoint = rootJoints.get(i); rootJoint.physics.recursiveComputeAngularMomentum(tempAngularMomentum); angularMomentum.add(tempAngularMomentum); } } /** * Computes the total angular momentum about the center of mass for the subtree rooted at the * specified root Joint. * * @param rootJoint Root Joint for which linear momentum is computed. * @param angularMomentum Total angular momentum vector that is computed. */ public void computeAngularMomentum(Joint rootJoint, Vector3DBasics angularMomentum) { angularMomentum.set(0.0, 0.0, 0.0); rootJoint.physics.recursiveComputeAngularMomentum(tempAngularMomentum); angularMomentum.add(tempAngularMomentum); } private Vector3D tempCOMVector = new Vector3D(); /** * Computes the Center of Mass location and total linear and angular momentum about the Center of * Mass for this Robot. * * @param comPoint Center of Mass point that is computed. * @param linearMomentum Total linear momentum vector that is computed. * @param angularMomentum Total angular momentum vector that is computed. * @return Total mass of the robot. */ public double computeCOMMomentum(Point3DBasics comPoint, Vector3DBasics linearMomentum, Vector3DBasics angularMomentum) { double mass = computeCenterOfMass(comPoint); computeLinearMomentum(linearMomentum); computeAngularMomentum(angularMomentum); // System.out.println("Angular Momentum about 0: " + angularMomentum); // Angular momentum is about 0,0,0. Transform to about com: tempCOMVector.set(comPoint); tempAngularMomentum.cross(tempCOMVector, linearMomentum); // System.out.println("Linear Momentum: " + linearMomentum); // System.out.println("com X linearMomentum: " + tempAngularMomentum); angularMomentum.sub(tempAngularMomentum); return mass; } /** * Computes the Center of Mass location and total linear and angular momentum about the center of * mass for the subtree rooted at the specified root Joint. * * @param rootJoint Root Joint to computed momentum from. * @param comPoint Center of Mass point that is computed. * @param linearMomentum Total linear momentum vector that is computed. * @param angularMomentum Total angular momentum vector that is computed. * @return Total mass of the robot. */ public double computeCOMMomentum(Joint rootJoint, Point3DBasics comPoint, Vector3DBasics linearMomentum, Vector3DBasics angularMomentum) { double mass = computeCenterOfMass(rootJoint, comPoint); computeLinearMomentum(rootJoint, linearMomentum); computeAngularMomentum(rootJoint, angularMomentum); // System.out.println("Angular Momentum about 0: " + angularMomentum); // Angular momentum is about 0,0,0. Transform to about com: tempCOMVector.set(comPoint); tempAngularMomentum.cross(tempCOMVector, linearMomentum); // System.out.println("Linear Momentum: " + linearMomentum); // System.out.println("com X linearMomentum: " + tempAngularMomentum); angularMomentum.sub(tempAngularMomentum); return mass; } private final Vector3D tempRVector = new Vector3D(); private final Vector3D tempRCrossF = new Vector3D(), tempForce = new Vector3D(); /** * Computes the Center of Pressure of the GroundContactPoints attached to this Robot. * * @param copPoint Center of Pressure point that is computed. * @param copForce Center of Pressure total force vector that is computed. * @param copMoment Total moment generated about the Center of Pressure from all the * GroundContactPoints. */ public void computeCenterOfPressure(Point3DBasics copPoint, Vector3DBasics copForce, Vector3DBasics copMoment) { copPoint.set(0.0, 0.0, 0.0); copForce.set(0.0, 0.0, 0.0); copMoment.set(0.0, 0.0, 0.0); List gcPoints = getAllGroundContactPoints(); for (int i = 0; i < gcPoints.size(); i++) { GroundContactPoint gc = gcPoints.get(i); gc.getForce(tempForce); copForce.add(tempForce); double fz = tempForce.getZ(); copPoint.setX(copPoint.getX() + gc.getX() * fz); copPoint.setY(copPoint.getY() + gc.getY() * fz); copPoint.setZ(copPoint.getZ() + gc.getZ() * fz); } if (copForce.getZ() < 1e-14) { copPoint.set(Double.NaN, Double.NaN, Double.NaN); copMoment.set(0.0, 0.0, 0.0); return; } copPoint.scale(1.0 / copForce.getZ()); for (int i = 0; i < gcPoints.size(); i++) { GroundContactPoint gc = gcPoints.get(i); tempRVector.setX(copPoint.getX() - gc.getX()); tempRVector.setY(copPoint.getY() - gc.getY()); tempRVector.setZ(copPoint.getZ() - gc.getZ()); gc.getForce(tempForce); tempRCrossF.cross(tempRVector, tempForce); copMoment.add(tempRCrossF); } } /** * This method returns the display name of the robot followed by the names of each joint. * * @return String, display name of the robot */ @Override public String toString() { StringBuffer retBuffer = new StringBuffer(); Queue queue = new LinkedList<>(); retBuffer.append("Robot: " + name + "\n\n"); List children = this.getRootJoints(); queue.addAll(children); while (!queue.isEmpty()) { Joint joint = queue.poll(); retBuffer.append("\n" + joint.toString()); List childrenJoints = joint.getChildrenJoints(); queue.addAll(childrenJoints); } return retBuffer.toString(); } public void printRobotJointsAndMasses(StringBuffer stringBuffer) { Queue queue = new LinkedList<>(); List children = this.getRootJoints(); queue.addAll(children); while (!queue.isEmpty()) { Joint joint = queue.poll(); stringBuffer.append("\n" + joint.getName() + ": mass = " + joint.getLink().getMass()); List childrenJoints = joint.getChildrenJoints(); queue.addAll(childrenJoints); } } /** * {@literal Outputs a Java class which can be used as a base for this Robot's RobotController. This * class contains all of the variables associated with the robot preregistered saving the user * time when creating their RobotController. The class will be a member of the same package as * parent Robot with a name of the following format: ControllerBase * For example, a robot named SpringFlamingoRobot would produce a controller base named SpringFlamingoControllerBase. * Any names not ending in robot are left untouched, therefore a robot named SpringRobotFlamingo would result in * a controller base named SpringRobotFlamingoControllerBase.} * * @param stream PrintStream to output the class to. Use System.out to output to the screen. */ // public void createControllerBase(PrintStream stream) // { // // Retrieve the class and package names // String name = this.getClass().getSimpleName(); // Robot Class // String baseName; // Name of ControllerBase // // Lets remove any Robot endings from the ControllerBase name // if (name.endsWith("Robot")) // baseName = name.substring(0, name.length() - "Robot".length()); // else // baseName = name; // // String packageName = this.getClass().getPackage().getName(); // Robot Package // // stream.println("package " + packageName + ";"); // stream.println(""); // stream.println("import us.ihmc.simulationconstructionset.*;"); // stream.println("import java.util.*;"); // stream.println(""); // stream.println("public class " + baseName + "ControllerBase implements YoRegistry"); // stream.println("{"); // println(stream, 3, "protected " + name + " rob;"); // stream.println(""); // println(stream, 3, "// These are the variables that are automatically created when the robot is created:"); // //println(stream, 3, "YoVariable t;"); // // //VarList robVariables = new VarList("Robot Variables"); // // Print the joint variables: // this.printVarBase(stream, robVars); // stream.println(""); // this.printVarBase(stream, groundVars); // // //for(int jointNum = 0; jointNum < rootJoints.size(); jointNum++) // //{ // // Joint rootJoint = (Joint) rootJoints.get(jointNum); // // recursivelyPrintJointBase(rootJoint, stream, robVariables); // //} // // stream.println(""); // println(stream, 3, "// User defined control variables will be placed in this ArrayList when they are registered:"); // println(stream, 3, "ArrayList controlVars = new ArrayList();"); // println(stream, 3, "LinkedHashMap controlVarsHashMap = new LinkedHashMap();"); // stream.println(""); // println(stream, 3, "public " + baseName + "ControllerBase(" + name + " rob)"); // println(stream, 3, "{"); // println(stream, 5, "this.rob = rob;"); // stream.println(""); // println(stream, 5, "// Get the variables that are stored with the robot:"); // stream.println(""); // // //println(stream, 5, "t = rob.getVar(\"t\");"); // stream.println(""); // // // // for(int varNum=0; varNumControllerBase * For example, a robot named SpringFlamingoRobot would produce a controller base named SpringFlamingoControllerBase. * Any names not ending in robot are left untouched, therefore a robot named SpringRobotFlamingo would result in * a controller base named SpringRobotFlamingoControllerBase.} * * @param file File where the code will be stored. Ensure that the name of this file corresponds to * the name of the class it contains. */ // public void createControllerBase(File file) // { // try // { // PrintStream stream = new PrintStream(file); // createControllerBase(stream); // } // catch (FileNotFoundException missing) // { // System.out.println("The file could not be written for this reason:\n\t" + missing.getMessage()); // } // } /** * {@literal Outputs a Java class which can be used as a base for this Robot's RobotController. This * class contains all of the variables associated with the robot preregistered saving the user * time when creating their RobotController. The file will be named <ThisRobotClassName * without 'Robot'>ControllerBase.java and stored in the same directory as the class file * that created it.} */ // public void createControllerBase() // { // File controllerBase; // try // { // controllerBase = new File(getPath().toURI()); // PrintStream stream = new PrintStream(controllerBase); // createControllerBase(stream); // } // catch (FileNotFoundException missing) // { // System.out.println("The specified file could not be created and generated the following error message:\n\t" + missing.getMessage()); // } // catch (URISyntaxException badFormat) // { // System.out.println("Path to " + this.getClass().getName() + " could not be calculated and the following error was observed:\n\t" + badFormat.getMessage()); // } // // } /** * Build a path to a new ControllerBase file in the same directory as the robot's .class file. * * @return URL containing the new file path. */ @SuppressWarnings("unused") private URL getPath() { Class c = this.getClass(); URL path; URL url = c.getResource(c.getSimpleName() + ".class"); if (url == null) return null; String temp = url.toExternalForm(); // First, attempt to remove just the name from the end. // For example, a path might be "C:/RobotStuff/Robot.class" // this would remove "/Robot.class" giving just the location // If the first attempt doesn't work, temp probably ends with // /.class; try to remove. // If that doesn't work either, try backslashes instead of // forward slashes. As a last resort return null. String end = "/" + c.getSimpleName() + ".class"; if (temp.endsWith(end)) { temp = temp.substring(0, temp.length() - end.length()); } else { end = "/" + c.getName().replace("\\.", "/") + ".class"; if (temp.endsWith(end)) { temp = temp.substring(0, temp.length() - end.length()); } else { end = end.replace("/", "\\"); if (temp.endsWith(end)) { temp = temp.substring(0, temp.length() - end.length()); } else return null; } } // Modify the path with the appropriate ControllerBase name. // For example, if this robot is named SpringFlamingo the controller // base would be SpringFlamingoControllerBase.java // If the name ends with "Robot", eg SpringFlamingoRobot, remove it. String temp2 = c.getSimpleName(); temp += "/" + ((temp2.endsWith("Robot")) ? temp2.substring(0, temp2.length() - "Robot".length()) : temp2) + "ControllerBase.java"; // Attempt to create the new URL try { path = new URL(temp); return path; } catch (MalformedURLException broken) { // Something is wrong with the path, tell the user System.err.println("Path to " + c.getName() + " could not be calculated and the following error was observed:\n\t" + broken.getMessage() + "\n\tPath: " + temp); return null; } } /** * Function used while generating the controller base code. * * @param stream PrintStream to output on. * @param indent Number of spaces to indent. * @param line Text to output. */ @SuppressWarnings("unused") private void println(PrintStream stream, int indent, String line) { for (int i = 0; i < indent; i++) { stream.print(" "); } stream.println(line); } /** * This method provides a convienent means to print out VarLists in a pretty class friendly form. * All variants of CreateControllerBase use this function during generation. * * @param stream PrintStream to output with. * @param list VarList to print. */ @SuppressWarnings("unused") private void printVarBase(PrintStream stream, YoVariableList list) { if (list.size() == 0) return; // Joint Variables stream.print(" YoVariable "); for (int varNum = 0; varNum < list.size(); varNum++) { YoVariable var = list.get(varNum); if (varNum != 0) { if (varNum % 10 == 0) { stream.println(";"); stream.print(" YoVariable "); } else stream.print(", "); } stream.print(var.getName()); } stream.println(";"); } public List getControllers() { return controllers; } public void setBodyExternalForcePoint(double fx, double fy, double fz) { kp_body.setForce(fx, fy, fz); } @Override public YoVariable findVariable(String variableName) { return getRobotsYoRegistry().findVariable(variableName); } @Override public boolean hasUniqueVariable(String variableName) { return getRobotsYoRegistry().hasUniqueVariable(variableName); } @Override public List getVariables() { return getRobotsYoRegistry().collectSubtreeVariables(); } @Override public YoVariable findVariable(String namespaceEnding, String name) { return getRobotsYoRegistry().findVariable(namespaceEnding, name); } @Override public boolean hasUniqueVariable(String namespaceEnding, String name) { return getRobotsYoRegistry().hasUniqueVariable(namespaceEnding, name); } @Override public List findVariables(String namespaceEnding, String name) { return getRobotsYoRegistry().findVariables(namespaceEnding, name); } @Override public List findVariables(String name) { return getRobotsYoRegistry().findVariables(name); } @Override public List findVariables(YoNamespace namespace) { return getRobotsYoRegistry().findVariables(namespace); } public List getStaticLinkGraphics() { return staticLinkGraphics; } public Link getLink(String linkName) { for (Joint rootJoint : rootJoints) { Link link = rootJoint.getLink(linkName); if (link != null) return link; } return null; } public void freezeJointAtZero(Joint jointToFreeze) { Vector3D jointToFreezeOffset = new Vector3D(); jointToFreeze.getOffset(jointToFreezeOffset); System.out.println("jointToFreezeOffset = " + jointToFreezeOffset); Joint parentJoint = jointToFreeze.getParentJoint(); parentJoint.removeChildJoint(jointToFreeze); Link parentLink = parentJoint.getLink(); parentLink = Link.combineLinks(parentLink.getName(), parentLink, jointToFreeze.getLink(), jointToFreezeOffset); parentJoint.setLink(parentLink); List jointsToMove = new ArrayList<>(); List childrenJoints = jointToFreeze.getChildrenJoints(); for (Joint childJoint : childrenJoints) { jointsToMove.add(childJoint); Vector3D childOffset = new Vector3D(); childJoint.getOffset(childOffset); childOffset.add(jointToFreezeOffset); childJoint.setOffset(childOffset); } for (Joint jointToMove : jointsToMove) { jointToFreeze.removeChildJoint(jointToMove); parentJoint.addJoint(jointToMove); } } public boolean verifySetupProperly(double epsilon) { for (Joint rootJoint : rootJoints) { boolean rootJointSetupProperly = rootJoint.physics.verifySetupProperly(epsilon); if (!rootJointSetupProperly) return false; } return true; } public Joint getJoint(String name) { for (int i = 0; i < rootJoints.size(); i++) { Joint rootJoint = rootJoints.get(i); Joint joint = rootJoint.recursivelyGetJoint(name); if (joint != null) return joint; } return null; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy