Skip to content

Commit

Permalink
Merge branch 'release/0.0.7'
Browse files Browse the repository at this point in the history
  • Loading branch information
Sylvain Bertrand committed Nov 8, 2018
2 parents 3de2637 + 5f66441 commit 82a977c
Show file tree
Hide file tree
Showing 4 changed files with 180 additions and 41 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ apply plugin: "us.ihmc.ihmc-build"

ihmc {
group = "us.ihmc"
version = "0.0.6"
version = "0.0.7"
vcsUrl = "https://github.com/ihmcrobotics/mecano"
openSource = true

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,10 @@ public void passOne()
localJointAcceleration.setBaseFrame(parent.getBodyFixedFrame());
rigidBodyAcceleration.add(localJointAcceleration);
}
else
{
rigidBodyAcceleration.setBodyFrame(getBodyFixedFrame());
}

rigidBody.getInertia().computeDynamicWrenchFast(rigidBodyAcceleration, bodyTwistToUse, jointWrench);
}
Expand Down
92 changes: 52 additions & 40 deletions src/main/java/us/ihmc/mecano/tools/MultiBodySystemTools.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ public class MultiBodySystemTools
/**
* Retrieves and gets the root body of the multi-body system the given {@code body} belongs to.
*
* @param body an arbitrary body that belongs to the multi-body system that this method is to
* find the root.
* @param body an arbitrary body that belongs to the multi-body system that this method is to find
* the root.
* @return the root body.
*/
public static RigidBodyReadOnly getRootBody(RigidBodyReadOnly body)
Expand All @@ -45,8 +45,8 @@ public static RigidBodyReadOnly getRootBody(RigidBodyReadOnly body)
/**
* Retrieves and gets the root body of the multi-body system the given {@code body} belongs to.
*
* @param body an arbitrary body that belongs to the multi-body system that this method is to
* find the root.
* @param body an arbitrary body that belongs to the multi-body system that this method is to find
* the root.
* @return the root body.
*/
public static RigidBodyBasics getRootBody(RigidBodyBasics body)
Expand Down Expand Up @@ -124,13 +124,13 @@ public static JointReadOnly[] createJointPath(RigidBodyReadOnly start, RigidBody
}

/**
* Traverses up the kinematic chain from the candidate descendant towards the root body, checking
* to see if each parent body is the ancestor in question.
* Traverses up the kinematic chain from the candidate descendant towards the root body, checking to
* see if each parent body is the ancestor in question.
*
* @param candidateDescendant the query for the descendant. A rigid-body is the descendant of
* another rigid-body if it is between the other rigid-body and an end-effector.
* @param ancestor the query for the ancestor. A rigid-body is the ancestor of another rigid-body
* if it is between the other rigid-body and the root body.
* @param ancestor the query for the ancestor. A rigid-body is the ancestor of another rigid-body if
* it is between the other rigid-body and the root body.
* @return {@code true} if {@code candidateDescendant} is a descendant of {@code ancestor},
* {@code false} otherwise.
*/
Expand All @@ -152,16 +152,16 @@ public static boolean isAncestor(RigidBodyReadOnly candidateDescendant, RigidBod
/**
* Computes the number of joints that separates the {@code descendant} from its {@code ancestor}.
* <p>
* The {@code ancestor} is expected to be located between the root body and the
* {@code descendant}, if not this method returns {@code -1}.
* The {@code ancestor} is expected to be located between the root body and the {@code descendant},
* if not this method returns {@code -1}.
* </p>
*
* @param descendant the descendant, often it is the end-effector.
* @param ancestor the ancestor of the descendant, often it is the root body.
* @return the distance in number of joints between the {@code descendant} and the
* {@code ancestor}. This method returns {@code 0} if the two rigid-bodies are the same.
* This method returns {@code -1} if the given {@code ancestor} is not located between
* the {@code descendant} and the root body.
* @return the distance in number of joints between the {@code descendant} and the {@code ancestor}.
* This method returns {@code 0} if the two rigid-bodies are the same. This method returns
* {@code -1} if the given {@code ancestor} is not located between the {@code descendant}
* and the root body.
*/
public static int computeDistanceToAncestor(RigidBodyReadOnly descendant, RigidBodyReadOnly ancestor)
{
Expand Down Expand Up @@ -189,8 +189,8 @@ public static int computeDistanceToAncestor(RigidBodyReadOnly descendant, RigidB
* @return the number of degrees of freedom.
* @throws RuntimeException if the given ancestor and descendant are swapped, or if the do not
* belong to the same system.
* @throws RuntimeException this method does not support in kinematic trees to go through
* different branches.
* @throws RuntimeException this method does not support in kinematic trees to go through different
* branches.
*/
public static int computeDegreesOfFreedom(RigidBodyReadOnly ancestor, RigidBodyReadOnly descendant)
{
Expand Down Expand Up @@ -262,6 +262,21 @@ public static RigidBodyBasics[] collectSuccessors(JointBasics... joints)
return Stream.of(joints).map(JointBasics::getSuccessor).toArray(RigidBodyBasics[]::new);
}

/**
* Collects any rigid-body that composes any of the subtrees originating at the given
* {@code joints}.
* <p>
* WARNING: This method generates garbage.
* </p>
*
* @param joints the joints indicating the start of each subtree to collect.
* @return the array containing all the rigid-bodies composing the subtrees.
*/
public static RigidBodyBasics[] collectSubtreeSuccessors(JointBasics... joints)
{
return Stream.of(joints).map(JointBasics::getSuccessor).flatMap(RigidBodyBasics::subtreeStream).distinct().toArray(RigidBodyBasics[]::new);
}

/**
* Collects for each rigid-body all their support joints, i.e. the joints that are between the
* rigid-body and the root body, and returns an array containing no duplicate elements.
Expand Down Expand Up @@ -307,8 +322,7 @@ public static <T extends JointReadOnly> List<T> filterJoints(List<? extends Join
* Collects only the joints from {@code source} that are instances of the given {@code clazz} and
* stores them in {@code destination}.
* <p>
* The filtered joints are added to the end of {@code destination} using
* {@link List#add(Object)}.
* The filtered joints are added to the end of {@code destination} using {@link List#add(Object)}.
* </p>
*
* @param source the original collection of joints to filter. Not modified.
Expand Down Expand Up @@ -393,8 +407,8 @@ public static <T extends JointReadOnly> int filterJoints(JointReadOnly[] source,
* multi-body system they belong.
* <li>the last joint of the array should be the closest or equal to one of the leaves or
* end-effectors of the multi-body system they belong.
* <li>the continuity test asserts that each pair of successive joints in the given array are
* also successive in the kinematic chain:
* <li>the continuity test asserts that each pair of successive joints in the given array are also
* successive in the kinematic chain:
* {@code joints[i] == joints[i+1].getPredecessor().getParentJoint()} &forall; i &in; [0;
* {@code joints.length - 1}].
* </ul>
Expand All @@ -421,8 +435,8 @@ public static boolean areJointsInContinuousOrder(JointReadOnly[] joints)
* <p>
* More precisely:
* <ul>
* <li>the first joint of the list should be the closest or equal to the root body of the
* multi-body system they belong.
* <li>the first joint of the list should be the closest or equal to the root body of the multi-body
* system they belong.
* <li>the last joint of the list should be the closest or equal to one of the leaves or
* end-effectors of the multi-body system they belong.
* <li>the continuity test asserts that each pair of successive joints in the given list are also
Expand Down Expand Up @@ -542,13 +556,12 @@ private static void copyJointsTau(List<? extends JointReadOnly> source, List<? e
}

/**
* Iterates through the given {@code joints}, extract the requested state {@code stateSelection}
* for each joint, and finally stores the states in order in the given matrix
* {@code matrixToPack}.
* Iterates through the given {@code joints}, extract the requested state {@code stateSelection} for
* each joint, and finally stores the states in order in the given matrix {@code matrixToPack}.
*
* @param joints the joints to extract the state of. Not modified.
* @param stateSelection indicates what state is to be extract, i.e. it can be either
* configuration, velocity, acceleration, or tau (or effort).
* @param stateSelection indicates what state is to be extract, i.e. it can be either configuration,
* velocity, acceleration, or tau (or effort).
* @param matrixToPack the matrix in which the state of the joints is to be stored. Modified.
* @return the number of rows used to store the information in the matrix.
*/
Expand Down Expand Up @@ -614,13 +627,12 @@ private static int extractJointsTau(List<? extends JointReadOnly> joints, int st
}

/**
* Iterates through the given {@code joints}, extract the requested state {@code stateSelection}
* for each joint, and finally stores the states in order in the given matrix
* {@code matrixToPack}.
* Iterates through the given {@code joints}, extract the requested state {@code stateSelection} for
* each joint, and finally stores the states in order in the given matrix {@code matrixToPack}.
*
* @param joints the joints to extract the state of. Not modified.
* @param stateSelection indicates what state is to be extract, i.e. it can be either
* configuration, velocity, acceleration, or tau (or effort).
* @param stateSelection indicates what state is to be extract, i.e. it can be either configuration,
* velocity, acceleration, or tau (or effort).
* @param matrixToPack the matrix in which the state of the joints is to be stored. Modified.
* @return the number of rows used to store the information in the matrix.
*/
Expand Down Expand Up @@ -691,10 +703,10 @@ private static int extractJointsTau(JointReadOnly[] joints, int startIndex, Dens
* stored in the proper order.
*
* @param joints the joints to update the state of. Modified.
* @param stateSelection indicates what state is to be updated, i.e. it can be either
* configuration, velocity, acceleration, or tau (or effort).
* @param matrix the matrix in which the new state of the joints is stored. The data is expected
* to be stored as a column vector starting at the first row. Modified.
* @param stateSelection indicates what state is to be updated, i.e. it can be either configuration,
* velocity, acceleration, or tau (or effort).
* @param matrix the matrix in which the new state of the joints is stored. The data is expected to
* be stored as a column vector starting at the first row. Modified.
* @return the number of rows that were used from the matrix.
*/
public static int insertJointsState(List<? extends JointBasics> joints, JointStateType stateSelection, DenseMatrix64F matrix)
Expand Down Expand Up @@ -764,10 +776,10 @@ private static int insertJointsTau(List<? extends JointBasics> joints, int start
* stored in the proper order.
*
* @param joints the joints to update the state of. Modified.
* @param stateSelection indicates what state is to be updated, i.e. it can be either
* configuration, velocity, acceleration, or tau (or effort).
* @param matrix the matrix in which the new state of the joints is stored. The data is expected
* to be stored as a column vector starting at the first row. Modified.
* @param stateSelection indicates what state is to be updated, i.e. it can be either configuration,
* velocity, acceleration, or tau (or effort).
* @param matrix the matrix in which the new state of the joints is stored. The data is expected to
* be stored as a column vector starting at the first row. Modified.
* @return the number of rows that were used from the matrix.
*/
public static int insertJointsState(JointBasics[] joints, JointStateType stateSelection, DenseMatrix64F matrix)
Expand Down
123 changes: 123 additions & 0 deletions src/test/java/us/ihmc/mecano/tools/MultiBodySystemToolsTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package us.ihmc.mecano.tools;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.stream.Collectors;

import org.junit.Test;

import us.ihmc.mecano.multiBodySystem.interfaces.JointBasics;
import us.ihmc.mecano.multiBodySystem.interfaces.JointReadOnly;
import us.ihmc.mecano.multiBodySystem.interfaces.RigidBodyBasics;
import us.ihmc.mecano.multiBodySystem.interfaces.RigidBodyReadOnly;

public class MultiBodySystemToolsTest
{
public static final int ITERATIONS = 1000;

@Test
public void testCreateJointPath() throws Exception
{
Random random = new Random(34535);

for (int i = 0; i < ITERATIONS; i++)
{
int numberOfJoints = 100;
List<JointBasics> joints = MultiBodySystemRandomTools.nextJointTree(random, numberOfJoints);

RigidBodyBasics bodyA = joints.get(random.nextInt(numberOfJoints)).getSuccessor();
RigidBodyBasics bodyB = bodyA.subtreeList().get(random.nextInt(bodyA.subtreeList().size()));

JointReadOnly[] jointPath = MultiBodySystemTools.createJointPath(bodyA, bodyB);

assertNotNull(jointPath);

assertEquals(MultiBodySystemTools.computeDistanceToAncestor(bodyB, bodyA), jointPath.length);

if (bodyA != bodyB)
{
assertEquals(bodyA, jointPath[0].getPredecessor());
RigidBodyReadOnly expectedPredessor = null;
int nDoFs = 0;

for (JointReadOnly joint : jointPath)
{
if (expectedPredessor != null)
assertEquals(expectedPredessor, joint.getPredecessor());
expectedPredessor = joint.getSuccessor();
nDoFs += joint.getDegreesOfFreedom();
}

assertEquals(bodyB, jointPath[jointPath.length - 1].getSuccessor());

assertEquals(nDoFs, MultiBodySystemTools.computeDegreesOfFreedom(bodyA, bodyB));
}
}
}

@Test
public void testCollectSuccessors() throws Exception
{
Random random = new Random(235423);

for (int i = 0; i < ITERATIONS; i++)
{
int numberOfJoints = 100;
List<JointBasics> joints = MultiBodySystemRandomTools.nextJointTree(random, numberOfJoints);

List<JointBasics> jointSelection = joints.stream().filter(j -> random.nextInt(10) < 4).collect(Collectors.toList());
Collections.shuffle(jointSelection);

RigidBodyBasics[] successors = MultiBodySystemTools.collectSuccessors(jointSelection.toArray(new JointBasics[0]));

assertArrayEquals(jointSelection.stream().map(JointBasics::getSuccessor).toArray(RigidBodyBasics[]::new), successors);
}
}

@Test
public void testCollectSubtreeSuccessors() throws Exception
{
Random random = new Random(2354234);

for (int i = 0; i < ITERATIONS; i++)
{
int numberOfJoints = 20;
List<JointBasics> joints = MultiBodySystemRandomTools.nextJointTree(random, numberOfJoints);

List<JointBasics> jointSelection = joints.stream().filter(j -> random.nextInt(10) < 4).collect(Collectors.toList());
Collections.shuffle(jointSelection);

RigidBodyBasics[] subtreeSuccessors = MultiBodySystemTools.collectSubtreeSuccessors(jointSelection.toArray(new JointBasics[0]));

List<JointBasics> reducedJointSelection = new ArrayList<>();

for (JointBasics candidate : jointSelection)
{
if (reducedJointSelection.contains(candidate))
continue;

if (jointSelection.stream().filter(joint -> joint != candidate)
.anyMatch(joint -> MultiBodySystemTools.isAncestor(candidate.getSuccessor(), joint.getSuccessor())))
continue;

reducedJointSelection.add(candidate);
}

Set<RigidBodyBasics> jointPredecessors = reducedJointSelection.stream().map(JointBasics::getPredecessor).collect(Collectors.toSet());

for (RigidBodyBasics subtreeSuccessor : subtreeSuccessors)
{
assertTrue(jointPredecessors.stream().anyMatch(subtreePredecessor -> MultiBodySystemTools.isAncestor(subtreeSuccessor, subtreePredecessor)));
assertTrue(jointPredecessors.stream().noneMatch(subtreePredecessor -> MultiBodySystemTools.isAncestor(subtreePredecessor, subtreeSuccessor)));
}
}
}
}

0 comments on commit 82a977c

Please sign in to comment.