예제 #1
0
def checkStaticConvergence(filterClass, performTest=True):
    """
    Test that an orientation estimation algorithm converges within a reasonable
    number of samples
    """
    gyro = np.zeros((3, 1))
    accel = -GRAVITY
    mag = NORTH
    SAMPLES = 500

    initialRotation = Quaternion.fromEuler((60, 45, 0))

    filter = filterClass(initialRotation=initialRotation,
                         initialTime=0,
                         initialRotationalVelocity=np.zeros((3, 1)),
                         **filterParameters.get(filterClass, {}))

    estimatedQuaternions = QuaternionArray(np.empty((SAMPLES, 4)))

    for i in range(SAMPLES):
        filter(accel, mag, gyro, dt * (1 + i))
        estimatedQuaternions[i] = filter.rotation.latestValue

    if performTest:
        assertMaximumErrorAngle(Quaternion(), filter.rotation.latestValue, 2)

    return estimatedQuaternions
예제 #2
0
def checkStaticConvergence(filterClass, performTest=True):
    """
    Test that an orientation estimation algorithm converges within a reasonable
    number of samples
    """
    gyro = np.zeros((3,1))
    accel = -GRAVITY
    mag = NORTH
    SAMPLES = 500

    initialRotation = Quaternion.fromEuler((60,45,0))

    filter = filterClass(initialRotation = initialRotation,
            initialTime=0,
            initialRotationalVelocity = np.zeros((3,1)),
            **filterParameters.get(filterClass, {}))

    estimatedQuaternions = QuaternionArray(np.empty((SAMPLES,4)))

    for i in range(SAMPLES):
        filter(accel, mag, gyro, dt*(1+i))
        estimatedQuaternions[i] = filter.rotation.latestValue

    if performTest:
        assertMaximumErrorAngle(Quaternion(),
            filter.rotation.latestValue, 2)

    return estimatedQuaternions
예제 #3
0
    def _readMotionData(self):
        '''
        Read the motion data from the BVH file.
        '''
        # update joint tree with new data.
        frame = 0
        lastRotation = {}
        for frame in range(self.frameCount):
            time = frame * self.framePeriod
            channelData = self._readFrame()
            for joint in self.model.joints:
                for chan in joint.channels:
                    chanData = channelData.pop(0)
                    if chan == "Xposition":
                        xPos = chanData
                    elif chan == "Yposition":
                        yPos = chanData
                    elif chan == "Zposition":
                        zPos = chanData
                    elif chan == "Xrotation":
                        xRot = chanData
                    elif chan == "Yrotation":
                        yRot = chanData
                    elif chan == "Zrotation":
                        zRot = chanData
                    else:
                        raise RuntimeError('Unknown channel: ' + chan)

                if not joint.hasParent:
                    try:
                        p = np.array([[xPos,yPos,zPos]]).T * \
                                self.conversionFactor
                        p = convertCGtoNED(p)
                        del xPos, yPos, zPos
                        joint.positionKeyFrames.add(time, p)
                    except UnboundLocalError:
                        raise SyntaxError("No position data for root joint")

                try:
                    if joint.hasChildren:
                        q = Quaternion.fromEuler((zRot, xRot, yRot),
                                                 order='zxy')
                        q = convertCGtoNED(q)
                        del xRot, yRot, zRot
                        # Rotation in BVH is relative to parent joint so
                        # combine the rotations
                        if joint.hasParent:
                            q = lastRotation[joint.parent] * q
                        joint.rotationKeyFrames.add(time, q)
                        lastRotation[joint] = q
                except UnboundLocalError:
                    raise SyntaxError("No rotation data for a joint that "
                                      "is not an end effector")
예제 #4
0
def testBVHInput():
    data = r"""HIERARCHY
ROOT root
{
    OFFSET 0.0 0.0 0.0
    CHANNELS 6 Xposition Yposition Zposition Zrotation Xrotation Yrotation
    JOINT j1
    {
        OFFSET 10.0 0.0 0.0
        CHANNELS 3 Zrotation Xrotation Yrotation
        End Site
        {
            OFFSET 0.0 10.0 0.0
        }
    }
}
MOTION
Frames: 1
Frame Time: 0.1
0.0 0.0 0.0 0.0 0.0 0.0 90.0 0.0 0.0
    """
    testFile = tempfile.NamedTemporaryFile(mode='w+t', encoding='utf-8')
    with testFile:
        testFile.write(data)
        testFile.flush()
        model = loadBVHFile(testFile.name)

        assert len(list(model.points)) == 3

        assert model.name == 'root'
        assert len(model.channels) == 6
        assert len(model.children) == 1
        assert_almost_equal(model.position(0), vector(0, 0, 0))
        assertQuaternionAlmostEqual(model.rotation(0),
                                    convertCGtoNED(Quaternion(1, 0, 0, 0)))

        j1 = model.getJoint('j1')
        assert j1.parent is model
        assert len(j1.channels) == 3
        assert len(j1.children) == 1
        assert_almost_equal(j1.positionOffset, vector(10, 0, 0))
        assert_almost_equal(j1.position(0), convertCGtoNED(vector(10, 0, 0)))
        assertQuaternionAlmostEqual(
            j1.rotation(0),
            convertCGtoNED(Quaternion.fromEuler((90, 0, 0), order='zxy')))

        j1end = model.getPoint('j1_end')
        assert j1end.parent is j1
        assert len(j1end.channels) == 0
        assert not j1end.isJoint
        assert_almost_equal(j1end.positionOffset, vector(0, 10, 0))
        assert_almost_equal(j1end.position(0), vector(0, 0, 0))
def checkVectorObservation(vectorObservationMethod, eulerAngles, inclination):
    if issubclass(vectorObservationMethod,
                  vector_observation.LeastSquaresOptimalVectorObservation):
        vo = vectorObservationMethod(inclinationAngle=inclination)
    else:
        vo = vectorObservationMethod()
    q = Quaternion.fromEuler(eulerAngles)
    inclination = math.radians(inclination)
    m = np.array([[math.cos(inclination)], [0], [math.sin(inclination)]])
    g = np.array([[0, 0, 1]], dtype=float).T
    g = q.rotateFrame(g)
    m = q.rotateFrame(m)
    assertQuaternionAlmostEqual(q, vo(g, m))
예제 #6
0
def testBVHInput():
    data = r"""HIERARCHY
ROOT root
{
    OFFSET 0.0 0.0 0.0
    CHANNELS 6 Xposition Yposition Zposition Zrotation Xrotation Yrotation
    JOINT j1
    {
        OFFSET 10.0 0.0 0.0
        CHANNELS 3 Zrotation Xrotation Yrotation
        End Site
        {
            OFFSET 0.0 10.0 0.0
        }
    }
}
MOTION
Frames: 1
Frame Time: 0.1
0.0 0.0 0.0 0.0 0.0 0.0 90.0 0.0 0.0
    """
    testFile = tempfile.NamedTemporaryFile()
    with testFile:
        testFile.write(data)
        testFile.flush()
        model = loadBVHFile(testFile.name)

        assert len(list(model.points)) == 3

        assert model.name == 'root'
        assert len(model.channels) == 6
        assert len(model.children) == 1
        assert_almost_equal(model.position(0),vector(0,0,0))
        assertQuaternionAlmostEqual(model.rotation(0),
               convertCGtoNED(Quaternion(1,0,0,0)))

        j1 = model.getJoint('j1')
        assert j1.parent is model
        assert len(j1.channels) == 3
        assert len(j1.children) == 1
        assert_almost_equal(j1.positionOffset, vector(10,0,0))
        assert_almost_equal(j1.position(0), convertCGtoNED(vector(10,0,0)))
        assertQuaternionAlmostEqual(j1.rotation(0),
               convertCGtoNED(Quaternion.fromEuler((90, 0, 0), order='zxy')))

        j1end = model.getPoint('j1_end')
        assert j1end.parent is j1
        assert len(j1end.channels) == 0
        assert not j1end.isJoint
        assert_almost_equal(j1end.positionOffset, vector(0,10,0))
        assert_almost_equal(j1end.position(0), vector(0,0,0))
예제 #7
0
def checkVectorObservation(vectorObservationMethod, eulerAngles, inclination):
    if issubclass(vectorObservationMethod,
            vector_observation.LeastSquaresOptimalVectorObservation):
        vo = vectorObservationMethod(inclinationAngle=inclination)
    else:
        vo = vectorObservationMethod()
    q = Quaternion.fromEuler(eulerAngles)
    inclination = math.radians(inclination)
    m = np.array([[math.cos(inclination)],[0],
        [math.sin(inclination)]])
    g = np.array([[0,0,1]],dtype=float).T
    g = q.rotateFrame(g)
    m = q.rotateFrame(m)
    assertQuaternionAlmostEqual(q,vo(g,m))
예제 #8
0
    def __init__(self, rootdata):
        """
        Construct a new ASFRoot.

        @param rootdata: The L{ParseResults} object representing the root
            segment data from the ASF file.
        """
        TreeNode.__init__(self, None)
        self.name = 'root'
        self.childoffset = vector(0,0,0)
        self.isDummy = False
        axis = vector(*rootdata.axis)[::-1]
        rotOrder = rootdata.axisRotationOrder[::-1]
        self.rotationOffset = Quaternion.fromEuler(axis, rotOrder).conjugate
        self.channels = rootdata.channels
예제 #9
0
    def __init__(self, rootdata):
        """
        Construct a new ASFRoot.

        @param rootdata: The L{ParseResults} object representing the root
            segment data from the ASF file.
        """
        TreeNode.__init__(self, None)
        self.name = 'root'
        self.childoffset = vector(0, 0, 0)
        self.isDummy = False
        axis = vector(*rootdata.axis)[::-1]
        rotOrder = rootdata.axisRotationOrder[::-1]
        self.rotationOffset = Quaternion.fromEuler(axis, rotOrder).conjugate
        self.channels = rootdata.channels
def geodesicQuaternionPath():
    """
    Generate an array of quaternions following a geodesic path

    Returns
    -------
    t : :class:`~numpy.ndarray`
        timestamps of quaternions
    quaternionPath : :class:`~imusim.maths.quaternions.QuaternionArray`
        array of quaternions following a geodesic path
    """

    t = np.arange(0,10,0.1)
    q = Quaternion.fromEuler((45,0,0))

    return t, QuaternionArray([q**T for T in t])
예제 #11
0
    def __init__(self, parent, bonedata, scale):
        """
        Consruct a new ASFBone.

        @param parent: The parent bone of this bone.
        @param bonedata: The L{ParseResults} object representing the bone
            data from the ASF file.
        """
        TreeNode.__init__(self, parent)
        self.name = bonedata.name
        axis = vector(*bonedata.axis)[::-1]
        rotOrder = bonedata.axisRotationOrder[::-1]
        self.rotationOffset = Quaternion.fromEuler(axis, rotOrder).conjugate
        self.childoffset = self.rotationOffset.rotateVector(
                vector(*bonedata.direction) * bonedata.length * scale)
        self.isDummy = bonedata.channels is ''
        self.channels = bonedata.channels
예제 #12
0
    def __init__(self, parent, bonedata, scale):
        """
        Consruct a new ASFBone.

        @param parent: The parent bone of this bone.
        @param bonedata: The L{ParseResults} object representing the bone
            data from the ASF file.
        """
        TreeNode.__init__(self, parent)
        self.name = bonedata.name
        axis = vector(*bonedata.axis)[::-1]
        rotOrder = bonedata.axisRotationOrder[::-1]
        self.rotationOffset = Quaternion.fromEuler(axis, rotOrder).conjugate
        self.childoffset = self.rotationOffset.rotateVector(
            vector(*bonedata.direction) * bonedata.length * scale)
        self.isDummy = bonedata.channels is ''
        self.channels = bonedata.channels
예제 #13
0
def loadASFFile(asfFileName, amcFileName, scaleFactor, framePeriod):
    """
    Load motion capture data from an ASF and AMC file pair.

    @param asfFileName: Name of the ASF file containing the description of
        the rigid body model
    @param amcFileName: Name of the AMC file containing the motion data
    @param scaleFactor: Scaling factor to convert lengths to m. For data
        from the CMU motion capture corpus this should be 2.54/100 to
        convert from inches to metres.

    @return: A {SampledBodyModel} representing the root of the rigid body
        model structure.
    """
    with open(asfFileName, 'r') as asfFile:
        data = asfParser.parseFile(asfFile)
        scale = (1.0/data.units.get('length',1)) * scaleFactor

        bones = dict((bone.name,bone) for bone in data.bones)
        asfModel = ASFRoot(data.root)

        for entry in data.hierarchy:
            parent = asfModel.getBone(entry.parent)
            for childName in entry.children:
                ASFBone(parent, bones[childName], scale)

        imusimModel = SampledBodyModel('root')
        for subtree in asfModel.children:
            for bone in subtree:
                if not bone.isDummy:
                    offset = vector(0,0,0)
                    ancestors = bone.ascendTree()
                    while True:
                        ancestor = ancestors.next().parent
                        offset += ancestor.childoffset
                        if not ancestor.isDummy:
                            break

                    SampledJoint(parent=imusimModel.getJoint(ancestor.name),
                            name=bone.name,
                            offset=offset)
                if not bone.hasChildren:
                    PointTrajectory(
                            parent=imusimModel.getJoint(bone.name),
                            name=bone.name+'_end',
                            offset=bone.childoffset
                            )

        with open(amcFileName) as amcFile:
            motion = amcParser.parseFile(amcFile)
            t = 0
            for frame in motion.frames:
                for bone in frame.bones:
                    bonedata = asfModel.getBone(bone.name)
                    if bone.name == 'root':
                        data = dict((chan.lower(), v) for chan,v in
                            zip(bonedata.channels,bone.channels))
                        position = convertCGtoNED(scale * vector(data['tx'],
                            data['ty'],data['tz']))
                        imusimModel.positionKeyFrames.add(t, position)

                    axes, angles = zip(*[(chan[-1], angle) for chan, angle in
                        zip(bonedata.channels, bone.channels) if
                                chan.lower().startswith('r')])
                    rotation = (bonedata.rotationOffset.conjugate *
                            Quaternion.fromEuler(angles[::-1], axes[::-1]))
                    joint = imusimModel.getJoint(bone.name)
                    if joint.hasParent:
                        parentRot = joint.parent.rotationKeyFrames.latestValue
                        parentRotOffset = bonedata.parent.rotationOffset
                        rotation = parentRot * parentRotOffset * rotation
                    else:
                        rotation = convertCGtoNED(rotation)
                    joint.rotationKeyFrames.add(t, rotation)
                t += framePeriod

        return imusimModel
예제 #14
0
def loadASFFile(asfFileName, amcFileName, scaleFactor, framePeriod):
    """
    Load motion capture data from an ASF and AMC file pair.

    @param asfFileName: Name of the ASF file containing the description of
        the rigid body model
    @param amcFileName: Name of the AMC file containing the motion data
    @param scaleFactor: Scaling factor to convert lengths to m. For data
        from the CMU motion capture corpus this should be 2.54/100 to
        convert from inches to metres.

    @return: A {SampledBodyModel} representing the root of the rigid body
        model structure.
    """
    with open(asfFileName, 'r') as asfFile:
        data = asfParser.parseFile(asfFile)
        scale = (1.0 / data.units.get('length', 1)) * scaleFactor

        bones = dict((bone.name, bone) for bone in data.bones)
        asfModel = ASFRoot(data.root)

        for entry in data.hierarchy:
            parent = asfModel.getBone(entry.parent)
            for childName in entry.children:
                ASFBone(parent, bones[childName], scale)

        imusimModel = SampledBodyModel('root')
        for subtree in asfModel.children:
            for bone in subtree:
                if not bone.isDummy:
                    offset = vector(0, 0, 0)
                    ancestors = bone.ascendTree()
                    while True:
                        ancestor = ancestors.next().parent
                        offset += ancestor.childoffset
                        if not ancestor.isDummy:
                            break

                    SampledJoint(parent=imusimModel.getJoint(ancestor.name),
                                 name=bone.name,
                                 offset=offset)
                if not bone.hasChildren:
                    PointTrajectory(parent=imusimModel.getJoint(bone.name),
                                    name=bone.name + '_end',
                                    offset=bone.childoffset)

        with open(amcFileName) as amcFile:
            motion = amcParser.parseFile(amcFile)
            t = 0
            for frame in motion.frames:
                for bone in frame.bones:
                    bonedata = asfModel.getBone(bone.name)
                    if bone.name == 'root':
                        data = dict((chan.lower(), v) for chan, v in zip(
                            bonedata.channels, bone.channels))
                        position = convertCGtoNED(
                            scale * vector(data['tx'], data['ty'], data['tz']))
                        imusimModel.positionKeyFrames.add(t, position)

                    axes, angles = zip(*[(chan[-1], angle)
                                         for chan, angle in zip(
                                             bonedata.channels, bone.channels)
                                         if chan.lower().startswith('r')])
                    rotation = (bonedata.rotationOffset.conjugate *
                                Quaternion.fromEuler(angles[::-1], axes[::-1]))
                    joint = imusimModel.getJoint(bone.name)
                    if joint.hasParent:
                        parentRot = joint.parent.rotationKeyFrames.latestValue
                        parentRotOffset = bonedata.parent.rotationOffset
                        rotation = parentRot * parentRotOffset * rotation
                    else:
                        rotation = convertCGtoNED(rotation)
                    joint.rotationKeyFrames.add(t, rotation)
                t += framePeriod

        return imusimModel