Implement btMultiBodySphericalJointMotor, able to track a quaternion position target.

Expose this btMultiBodySphericalJointMotor through PyBullet.setJointMotorControlMultiDof
Expose PyBullet.getQuaternionSlerp
Improve PyBullet.setJointMotorControlMultiDof
Improve humanoidMotionCapture.py with slerp and using setJointMotorControlMultiDof
Expose  btMultiBody::spatialTransform
Fix btMultiBody::setupPlanar from DeepMimic codebase
Add support for multidof joints in btMultiBody::compTreeLinkVelocities, thanks to DeepMimic codebase @xbpeng
This commit is contained in:
erwincoumans
2018-11-13 14:32:18 -08:00
parent a06b5de7b6
commit 7dd524075c
13 changed files with 778 additions and 68 deletions

View File

@@ -818,6 +818,22 @@ B3_SHARED_API int b3JointControlSetDesiredPosition(b3SharedMemoryCommandHandle c
return 0; return 0;
} }
B3_SHARED_API int b3JointControlSetDesiredPositionMultiDof(b3SharedMemoryCommandHandle commandHandle, int qIndex, const double* position, int dofCount)
{
struct SharedMemoryCommand* command = (struct SharedMemoryCommand*)commandHandle;
b3Assert(command);
if ((qIndex >= 0) && ((qIndex + dofCount) < MAX_DEGREE_OF_FREEDOM) && dofCount > 0 && dofCount <= 4)
{
for (int dof = 0; dof < dofCount; dof++)
{
command->m_sendDesiredStateCommandArgument.m_desiredStateQ[qIndex + dof] = position[dof];
command->m_updateFlags |= SIM_DESIRED_STATE_HAS_Q;
command->m_sendDesiredStateCommandArgument.m_hasDesiredStateFlags[qIndex + dof] |= SIM_DESIRED_STATE_HAS_Q;
}
}
return 0;
}
B3_SHARED_API int b3JointControlSetKp(b3SharedMemoryCommandHandle commandHandle, int dofIndex, double value) B3_SHARED_API int b3JointControlSetKp(b3SharedMemoryCommandHandle commandHandle, int dofIndex, double value)
{ {
struct SharedMemoryCommand* command = (struct SharedMemoryCommand*)commandHandle; struct SharedMemoryCommand* command = (struct SharedMemoryCommand*)commandHandle;
@@ -870,6 +886,22 @@ B3_SHARED_API int b3JointControlSetDesiredVelocity(b3SharedMemoryCommandHandle c
return 0; return 0;
} }
B3_SHARED_API int b3JointControlSetDesiredVelocityMultiDof(b3SharedMemoryCommandHandle commandHandle, int dofIndex, const double* velocity, int dofCount)
{
struct SharedMemoryCommand* command = (struct SharedMemoryCommand*)commandHandle;
b3Assert(command);
if ((dofIndex >= 0) && ((dofIndex+ dofCount) < MAX_DEGREE_OF_FREEDOM) && dofCount>=0 && dofCount<=4)
{
for (int dof = 0; dof < dofCount; dof++)
{
command->m_sendDesiredStateCommandArgument.m_desiredStateQdot[dofIndex+dof] = velocity[dof];
command->m_updateFlags |= SIM_DESIRED_STATE_HAS_QDOT;
command->m_sendDesiredStateCommandArgument.m_hasDesiredStateFlags[dofIndex+dof] |= SIM_DESIRED_STATE_HAS_QDOT;
}
}
return 0;
}
B3_SHARED_API int b3JointControlSetMaximumForce(b3SharedMemoryCommandHandle commandHandle, int dofIndex, double value) B3_SHARED_API int b3JointControlSetMaximumForce(b3SharedMemoryCommandHandle commandHandle, int dofIndex, double value)
{ {
struct SharedMemoryCommand* command = (struct SharedMemoryCommand*)commandHandle; struct SharedMemoryCommand* command = (struct SharedMemoryCommand*)commandHandle;
@@ -5221,3 +5253,14 @@ B3_SHARED_API void b3InvertTransform(const double pos[3], const double orn[4], d
outOrn[2] = invOrn[2]; outOrn[2] = invOrn[2];
outOrn[3] = invOrn[3]; outOrn[3] = invOrn[3];
} }
B3_SHARED_API void b3QuaternionSlerp(const double startQuat[/*4*/], const double endQuat[/*4*/], double interpolationFraction, double outOrn[/*4*/])
{
b3Quaternion start(startQuat[0], startQuat[1], startQuat[2], startQuat[3]);
b3Quaternion end(endQuat[0], endQuat[1], endQuat[2], endQuat[3]);
b3Quaternion result = start.slerp(end, interpolationFraction);
outOrn[0] = result[0];
outOrn[1] = result[1];
outOrn[2] = result[2];
outOrn[3] = result[3];
}

View File

@@ -440,12 +440,15 @@ extern "C"
///Only use when controlMode is CONTROL_MODE_POSITION_VELOCITY_PD ///Only use when controlMode is CONTROL_MODE_POSITION_VELOCITY_PD
B3_SHARED_API int b3JointControlSetDesiredPosition(b3SharedMemoryCommandHandle commandHandle, int qIndex, double value); B3_SHARED_API int b3JointControlSetDesiredPosition(b3SharedMemoryCommandHandle commandHandle, int qIndex, double value);
B3_SHARED_API int b3JointControlSetDesiredPositionMultiDof(b3SharedMemoryCommandHandle commandHandle, int qIndex, const double* position, int dofCount);
B3_SHARED_API int b3JointControlSetKp(b3SharedMemoryCommandHandle commandHandle, int dofIndex, double value); B3_SHARED_API int b3JointControlSetKp(b3SharedMemoryCommandHandle commandHandle, int dofIndex, double value);
B3_SHARED_API int b3JointControlSetKd(b3SharedMemoryCommandHandle commandHandle, int dofIndex, double value); B3_SHARED_API int b3JointControlSetKd(b3SharedMemoryCommandHandle commandHandle, int dofIndex, double value);
B3_SHARED_API int b3JointControlSetMaximumVelocity(b3SharedMemoryCommandHandle commandHandle, int dofIndex, double maximumVelocity); B3_SHARED_API int b3JointControlSetMaximumVelocity(b3SharedMemoryCommandHandle commandHandle, int dofIndex, double maximumVelocity);
///Only use when controlMode is CONTROL_MODE_VELOCITY ///Only use when controlMode is CONTROL_MODE_VELOCITY
B3_SHARED_API int b3JointControlSetDesiredVelocity(b3SharedMemoryCommandHandle commandHandle, int dofIndex, double value); /* find a better name for dof/q/u indices, point to b3JointInfo */ B3_SHARED_API int b3JointControlSetDesiredVelocity(b3SharedMemoryCommandHandle commandHandle, int dofIndex, double value); /* find a better name for dof/q/u indices, point to b3JointInfo */
B3_SHARED_API int b3JointControlSetDesiredVelocityMultiDof(b3SharedMemoryCommandHandle commandHandle, int dofIndex, const double* velocity, int dofCount);
B3_SHARED_API int b3JointControlSetMaximumForce(b3SharedMemoryCommandHandle commandHandle, int dofIndex, double value); B3_SHARED_API int b3JointControlSetMaximumForce(b3SharedMemoryCommandHandle commandHandle, int dofIndex, double value);
///Only use if when controlMode is CONTROL_MODE_TORQUE, ///Only use if when controlMode is CONTROL_MODE_TORQUE,
B3_SHARED_API int b3JointControlSetDesiredForceTorque(b3SharedMemoryCommandHandle commandHandle, int dofIndex, double value); B3_SHARED_API int b3JointControlSetDesiredForceTorque(b3SharedMemoryCommandHandle commandHandle, int dofIndex, double value);
@@ -631,6 +634,7 @@ extern "C"
B3_SHARED_API void b3MultiplyTransforms(const double posA[/*3*/], const double ornA[/*4*/], const double posB[/*3*/], const double ornB[/*4*/], double outPos[/*3*/], double outOrn[/*4*/]); B3_SHARED_API void b3MultiplyTransforms(const double posA[/*3*/], const double ornA[/*4*/], const double posB[/*3*/], const double ornB[/*4*/], double outPos[/*3*/], double outOrn[/*4*/]);
B3_SHARED_API void b3InvertTransform(const double pos[/*3*/], const double orn[/*4*/], double outPos[/*3*/], double outOrn[/*4*/]); B3_SHARED_API void b3InvertTransform(const double pos[/*3*/], const double orn[/*4*/], double outPos[/*3*/], double outOrn[/*4*/]);
B3_SHARED_API void b3QuaternionSlerp(const double startQuat[/*4*/], const double endQuat[/*4*/], double interpolationFraction, double outOrn[/*4*/]);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@@ -149,6 +149,8 @@ bool PhysicsClientSharedMemory::getJointInfo(int bodyUniqueId, int jointIndex, b
if ((jointIndex >= 0) && (jointIndex < bodyJoints->m_jointInfo.size())) if ((jointIndex >= 0) && (jointIndex < bodyJoints->m_jointInfo.size()))
{ {
info = bodyJoints->m_jointInfo[jointIndex]; info = bodyJoints->m_jointInfo[jointIndex];
info.m_qSize = 0;
info.m_uSize = 0;
switch (info.m_jointType) switch (info.m_jointType)
{ {
case eSphericalType: case eSphericalType:

View File

@@ -13,6 +13,8 @@
#include "BulletDynamics/MLCPSolvers/btDantzigSolver.h" #include "BulletDynamics/MLCPSolvers/btDantzigSolver.h"
#include "BulletDynamics/MLCPSolvers/btSolveProjectedGaussSeidel.h" #include "BulletDynamics/MLCPSolvers/btSolveProjectedGaussSeidel.h"
#include "BulletDynamics/Featherstone/btMultiBodyMLCPConstraintSolver.h" #include "BulletDynamics/Featherstone/btMultiBodyMLCPConstraintSolver.h"
#include "BulletDynamics/Featherstone/btMultiBodySphericalJointMotor.h"
#include "BulletDynamics/Featherstone/btMultiBodyConstraintSolver.h" #include "BulletDynamics/Featherstone/btMultiBodyConstraintSolver.h"
#include "BulletDynamics/Featherstone/btMultiBodyPoint2Point.h" #include "BulletDynamics/Featherstone/btMultiBodyPoint2Point.h"
@@ -2711,7 +2713,8 @@ void PhysicsServerCommandProcessor::deleteDynamicsWorld()
bool PhysicsServerCommandProcessor::supportsJointMotor(btMultiBody* mb, int mbLinkIndex) bool PhysicsServerCommandProcessor::supportsJointMotor(btMultiBody* mb, int mbLinkIndex)
{ {
bool canHaveMotor = (mb->getLink(mbLinkIndex).m_jointType == btMultibodyLink::eRevolute || mb->getLink(mbLinkIndex).m_jointType == btMultibodyLink::ePrismatic); bool canHaveMotor = (mb->getLink(mbLinkIndex).m_jointType == btMultibodyLink::eRevolute
|| mb->getLink(mbLinkIndex).m_jointType == btMultibodyLink::ePrismatic);
return canHaveMotor; return canHaveMotor;
} }
@@ -2722,10 +2725,10 @@ void PhysicsServerCommandProcessor::createJointMotors(btMultiBody* mb)
for (int i = 0; i < numLinks; i++) for (int i = 0; i < numLinks; i++)
{ {
int mbLinkIndex = i; int mbLinkIndex = i;
float maxMotorImpulse = 1.f;
if (supportsJointMotor(mb, mbLinkIndex)) if (supportsJointMotor(mb, mbLinkIndex))
{ {
float maxMotorImpulse = 1.f;
int dof = 0; int dof = 0;
btScalar desiredVelocity = 0.f; btScalar desiredVelocity = 0.f;
btMultiBodyJointMotor* motor = new btMultiBodyJointMotor(mb, mbLinkIndex, dof, desiredVelocity, maxMotorImpulse); btMultiBodyJointMotor* motor = new btMultiBodyJointMotor(mb, mbLinkIndex, dof, desiredVelocity, maxMotorImpulse);
@@ -2737,6 +2740,13 @@ void PhysicsServerCommandProcessor::createJointMotors(btMultiBody* mb)
m_data->m_dynamicsWorld->addMultiBodyConstraint(motor); m_data->m_dynamicsWorld->addMultiBodyConstraint(motor);
motor->finalizeMultiDof(); motor->finalizeMultiDof();
} }
if (mb->getLink(mbLinkIndex).m_jointType == btMultibodyLink::eSpherical)
{
btMultiBodySphericalJointMotor* motor = new btMultiBodySphericalJointMotor(mb, mbLinkIndex, 1000*maxMotorImpulse);
mb->getLink(mbLinkIndex).m_userPtr = motor;
m_data->m_dynamicsWorld->addMultiBodyConstraint(motor);
motor->finalizeMultiDof();
}
} }
} }
@@ -2916,6 +2926,18 @@ bool PhysicsServerCommandProcessor::processImportedObjects(const char* fileName,
std::string* baseName = new std::string(u2b.getLinkName(u2b.getRootLinkIndex())); std::string* baseName = new std::string(u2b.getLinkName(u2b.getRootLinkIndex()));
m_data->m_strings.push_back(baseName); m_data->m_strings.push_back(baseName);
mb->setBaseName(baseName->c_str()); mb->setBaseName(baseName->c_str());
#if 0
btAlignedObjectArray<char> urdf;
mb->dumpUrdf(urdf);
FILE* f = fopen("e:/pybullet.urdf", "w");
if (f)
{
fwrite(&urdf[0], urdf.size(), 1, f);
fclose(f);
}
#endif
} }
else else
{ {
@@ -5811,6 +5833,74 @@ bool PhysicsServerCommandProcessor::processSendDesiredStateCommand(const struct
numMotors++; numMotors++;
} }
} }
if (mb->getLink(link).m_jointType == btMultibodyLink::eSpherical)
{
btMultiBodySphericalJointMotor* motor = (btMultiBodySphericalJointMotor*)mb->getLink(link).m_userPtr;
if (motor)
{
if ((clientCmd.m_sendDesiredStateCommandArgument.m_hasDesiredStateFlags[velIndex] & SIM_DESIRED_STATE_HAS_RHS_CLAMP) != 0)
{
motor->setRhsClamp(clientCmd.m_sendDesiredStateCommandArgument.m_rhsClamp[velIndex]);
}
bool hasDesiredPosOrVel = false;
btScalar kp = 0.f;
btScalar kd = 0.f;
btVector3 desiredVelocity(0, 0, 0);
if ((clientCmd.m_sendDesiredStateCommandArgument.m_hasDesiredStateFlags[velIndex] & SIM_DESIRED_STATE_HAS_QDOT) != 0)
{
hasDesiredPosOrVel = true;
desiredVelocity.setValue(
clientCmd.m_sendDesiredStateCommandArgument.m_desiredStateQdot[velIndex+0],
clientCmd.m_sendDesiredStateCommandArgument.m_desiredStateQdot[velIndex+1],
clientCmd.m_sendDesiredStateCommandArgument.m_desiredStateQdot[velIndex+2]);
kd = 0.1;
}
btQuaternion desiredPosition(0, 0, 0, 1);
if ((clientCmd.m_sendDesiredStateCommandArgument.m_hasDesiredStateFlags[posIndex] & SIM_DESIRED_STATE_HAS_Q) != 0)
{
hasDesiredPosOrVel = true;
desiredPosition.setValue(
clientCmd.m_sendDesiredStateCommandArgument.m_desiredStateQ[posIndex + 0],
clientCmd.m_sendDesiredStateCommandArgument.m_desiredStateQ[posIndex + 1],
clientCmd.m_sendDesiredStateCommandArgument.m_desiredStateQ[posIndex + 2],
clientCmd.m_sendDesiredStateCommandArgument.m_desiredStateQ[posIndex + 3]);
kp = 0.1;
}
if (hasDesiredPosOrVel)
{
if ((clientCmd.m_sendDesiredStateCommandArgument.m_hasDesiredStateFlags[velIndex] & SIM_DESIRED_STATE_HAS_KP) != 0)
{
kp = clientCmd.m_sendDesiredStateCommandArgument.m_Kp[velIndex];
}
if ((clientCmd.m_sendDesiredStateCommandArgument.m_hasDesiredStateFlags[velIndex] & SIM_DESIRED_STATE_HAS_KD) != 0)
{
kd = clientCmd.m_sendDesiredStateCommandArgument.m_Kd[velIndex];
}
motor->setVelocityTarget(desiredVelocity, kd);
//todo: instead of clamping, combine the motor and limit
//and combine handling of limit force and motor force.
//clamp position
//if (mb->getLink(link).m_jointLowerLimit <= mb->getLink(link).m_jointUpperLimit)
//{
// btClamp(desiredPosition, mb->getLink(link).m_jointLowerLimit, mb->getLink(link).m_jointUpperLimit);
//}
motor->setPositionTarget(desiredPosition, kp);
btScalar maxImp = 1000000.f * m_data->m_physicsDeltaTime;
if ((clientCmd.m_updateFlags & SIM_DESIRED_STATE_HAS_MAX_FORCE) != 0)
maxImp = clientCmd.m_sendDesiredStateCommandArgument.m_desiredStateForceTorque[velIndex] * m_data->m_physicsDeltaTime;
motor->setMaxAppliedImpulse(maxImp);
}
numMotors++;
}
}
velIndex += mb->getLink(link).m_dofCount; velIndex += mb->getLink(link).m_dofCount;
posIndex += mb->getLink(link).m_posVarCount; posIndex += mb->getLink(link).m_posVarCount;
} }
@@ -8039,7 +8129,6 @@ bool PhysicsServerCommandProcessor::processInitPoseCommand(const struct SharedMe
mb->setJointVelMultiDof(i, &clientCmd.m_initPoseArgs.m_initialStateQdot[uDofIndex]); mb->setJointVelMultiDof(i, &clientCmd.m_initPoseArgs.m_initialStateQdot[uDofIndex]);
} }
posVarCountIndex += mb->getLink(i).m_posVarCount; posVarCountIndex += mb->getLink(i).m_posVarCount;
uDofIndex += mb->getLink(i).m_dofCount; uDofIndex += mb->getLink(i).m_dofCount;
} }

View File

@@ -445,7 +445,7 @@ enum EnumSimDesiredStateUpdateFlags
SIM_DESIRED_STATE_HAS_KD = 4, SIM_DESIRED_STATE_HAS_KD = 4,
SIM_DESIRED_STATE_HAS_KP = 8, SIM_DESIRED_STATE_HAS_KP = 8,
SIM_DESIRED_STATE_HAS_MAX_FORCE = 16, SIM_DESIRED_STATE_HAS_MAX_FORCE = 16,
SIM_DESIRED_STATE_HAS_RHS_CLAMP = 32 SIM_DESIRED_STATE_HAS_RHS_CLAMP = 32,
}; };
enum EnumSimParamUpdateFlags enum EnumSimParamUpdateFlags

View File

@@ -8,11 +8,15 @@ p.connect(p.GUI)
import pybullet_data import pybullet_data
useMotionCapture=True useMotionCapture=True
useMotionCaptureReset=not useMotionCapture
p.setAdditionalSearchPath(pybullet_data.getDataPath()) p.setAdditionalSearchPath(pybullet_data.getDataPath())
path = pybullet_data.getDataPath()+"/motions/humanoid3d_backflip.txt" p.setPhysicsEngineParameter(numSolverIterations=200)
#path = pybullet_data.getDataPath()+"/motions/humanoid3d_backflip.txt"
path = pybullet_data.getDataPath()+"/motions/humanoid3d_cartwheel.txt"
p.loadURDF("plane.urdf") p.loadURDF("plane.urdf",[0,0,-1])
print("path = ", path) print("path = ", path)
with open(path, 'r') as f: with open(path, 'r') as f:
motion_dict = json.load(f) motion_dict = json.load(f)
@@ -31,6 +35,11 @@ humanoid = p.loadURDF("humanoid/humanoid.urdf", globalScaling=0.25)
for j in range (p.getNumJoints(humanoid)): for j in range (p.getNumJoints(humanoid)):
ji = p.getJointInfo(humanoid,j) ji = p.getJointInfo(humanoid,j)
targetPosition=[0]
if (ji[2] == p.JOINT_SPHERICAL):
targetPosition=[0,0,0,1]
#p.setJointMotorControlMultiDof(humanoid,j,p.POSITION_CONTROL,targetPosition, force=0)
#print(ji) #print(ji)
print("joint[",j,"].type=",jointTypes[ji[2]]) print("joint[",j,"].type=",jointTypes[ji[2]])
print("joint[",j,"].name=",ji[1]) print("joint[",j,"].name=",ji[1])
@@ -51,7 +60,7 @@ for j in range (p.getNumJoints(humanoid)):
paramIds.append(p.addUserDebugParameter(jointName.decode("utf-8"),-4,4,0)) paramIds.append(p.addUserDebugParameter(jointName.decode("utf-8"),-4,4,0))
print("jointName=",jointName, "at ", j) print("jointName=",jointName, "at ", j)
p.changeVisualShape(humanoid,14,rgbaColor=[1,0,0,1]) p.changeVisualShape(humanoid,2,rgbaColor=[1,0,0,1])
chest=1 chest=1
neck=2 neck=2
rightShoulder=3 rightShoulder=3
@@ -66,34 +75,115 @@ leftKnee=13
leftAnkle=14 leftAnkle=14
import time import time
p.setRealTimeSimulation(0)
while (1):
once=True
p.getCameraImage(320,200) p.getCameraImage(320,200)
frame = int(p.readUserDebugParameter(frameId)) maxForce=1000
while (p.isConnected()):
frameReal = p.readUserDebugParameter(frameId)
frame = int(frameReal)
frameNext = frame+1
if (frameNext >= numFrames):
frameNext = frame
frameFraction = frameReal - frame
#print("frameFraction=",frameFraction)
#print("frame=",frame)
#print("frameNext=", frameNext)
#getQuaternionSlerp
frameData = motion_dict['Frames'][frame] frameData = motion_dict['Frames'][frame]
frameDataNext = motion_dict['Frames'][frameNext]
#print("duration=",frameData[0]) #print("duration=",frameData[0])
#print(pos=[frameData]) #print(pos=[frameData])
basePos1 = [frameData[1],frameData[2],frameData[3]]
baseOrn1 = [frameData[5],frameData[6], frameData[7],frameData[4]] basePos1Start = [frameData[1],frameData[2],frameData[3]]
basePos1End = [frameDataNext[1],frameDataNext[2],frameDataNext[3]]
basePos1 = [basePos1Start[0]+frameFraction*(basePos1End[0]-basePos1Start[0]),
basePos1Start[1]+frameFraction*(basePos1End[1]-basePos1Start[1]),
basePos1Start[2]+frameFraction*(basePos1End[2]-basePos1Start[2])]
baseOrn1Start = [frameData[5],frameData[6], frameData[7],frameData[4]]
baseOrn1Next = [frameDataNext[5],frameDataNext[6], frameDataNext[7],frameDataNext[4]]
baseOrn1 = p.getQuaternionSlerp(baseOrn1Start,baseOrn1Next,frameFraction)
#pre-rotate to make z-up #pre-rotate to make z-up
y2zPos=[0,0,0] y2zPos=[0,0,0.0]
y2zOrn = p.getQuaternionFromEuler([1.57,0,0]) y2zOrn = p.getQuaternionFromEuler([1.57,0,0])
basePos,baseOrn = p.multiplyTransforms(y2zPos, y2zOrn,basePos1,baseOrn1) basePos,baseOrn = p.multiplyTransforms(y2zPos, y2zOrn,basePos1,baseOrn1)
p.resetBasePositionAndOrientation(humanoid, basePos,baseOrn) p.resetBasePositionAndOrientation(humanoid, basePos,baseOrn)
chestRot = [frameData[9],frameData[10],frameData[11],frameData[8]] # once=False
neckRot = [frameData[13],frameData[14],frameData[15],frameData[12]] chestRotStart = [frameData[9],frameData[10],frameData[11],frameData[8]]
rightHipRot = [frameData[17],frameData[18],frameData[19],frameData[16]] chestRotEnd = [frameDataNext[9],frameDataNext[10],frameDataNext[11],frameDataNext[8]]
rightKneeRot = [frameData[20]] chestRot = p.getQuaternionSlerp(chestRotStart,chestRotEnd,frameFraction)
rightAnkleRot = [frameData[22],frameData[23],frameData[24],frameData[21]]
rightShoulderRot = [frameData[26],frameData[27],frameData[28],frameData[25]] neckRotStart = [frameData[13],frameData[14],frameData[15],frameData[12]]
rightElbowRot = [frameData[29]] neckRotEnd= [frameDataNext[13],frameDataNext[14],frameDataNext[15],frameDataNext[12]]
leftHipRot = [frameData[31],frameData[32],frameData[33],frameData[30]] neckRot = p.getQuaternionSlerp(neckRotStart,neckRotEnd,frameFraction)
leftKneeRot = [frameData[34]]
leftAnkleRot = [frameData[36],frameData[37],frameData[38],frameData[35]] rightHipRotStart = [frameData[17],frameData[18],frameData[19],frameData[16]]
leftShoulderRot = [frameData[40],frameData[41],frameData[42],frameData[39]] rightHipRotEnd = [frameDataNext[17],frameDataNext[18],frameDataNext[19],frameDataNext[16]]
leftElbowRot = [frameData[43]] rightHipRot = p.getQuaternionSlerp(rightHipRotStart,rightHipRotEnd,frameFraction)
rightKneeRotStart = [frameData[20]]
rightKneeRotEnd = [frameDataNext[20]]
rightKneeRot = [rightKneeRotStart[0]+frameFraction*(rightKneeRotEnd[0]-rightKneeRotStart[0])]
rightAnkleRotStart = [frameData[22],frameData[23],frameData[24],frameData[21]]
rightAnkleRotEnd = [frameDataNext[22],frameDataNext[23],frameDataNext[24],frameDataNext[21]]
rightAnkleRot = p.getQuaternionSlerp(rightAnkleRotStart,rightAnkleRotEnd,frameFraction)
rightShoulderRotStart = [frameData[26],frameData[27],frameData[28],frameData[25]]
rightShoulderRotEnd = [frameDataNext[26],frameDataNext[27],frameDataNext[28],frameDataNext[25]]
rightShoulderRot = p.getQuaternionSlerp(rightShoulderRotStart,rightShoulderRotEnd,frameFraction)
rightElbowRotStart = [frameData[29]]
rightElbowRotEnd = [frameDataNext[29]]
rightElbowRot = [rightElbowRotStart[0]+frameFraction*(rightElbowRotEnd[0]-rightElbowRotStart[0])]
leftHipRotStart = [frameData[31],frameData[32],frameData[33],frameData[30]]
leftHipRotEnd = [frameDataNext[31],frameDataNext[32],frameDataNext[33],frameDataNext[30]]
leftHipRot = p.getQuaternionSlerp(leftHipRotStart,leftHipRotEnd,frameFraction)
leftKneeRotStart = [frameData[34]]
leftKneeRotEnd = [frameDataNext[34]]
leftKneeRot = [leftKneeRotStart[0] +frameFraction*(leftKneeRotEnd[0]-leftKneeRotStart[0]) ]
leftAnkleRotStart = [frameData[36],frameData[37],frameData[38],frameData[35]]
leftAnkleRotEnd = [frameDataNext[36],frameDataNext[37],frameDataNext[38],frameDataNext[35]]
leftAnkleRot = p.getQuaternionSlerp(leftAnkleRotStart,leftAnkleRotEnd,frameFraction)
leftShoulderRotStart = [frameData[40],frameData[41],frameData[42],frameData[39]]
leftShoulderRotEnd = [frameDataNext[40],frameDataNext[41],frameDataNext[42],frameDataNext[39]]
leftShoulderRot = p.getQuaternionSlerp(leftShoulderRotStart,leftShoulderRotEnd,frameFraction)
leftElbowRotStart = [frameData[43]]
leftElbowRotEnd = [frameDataNext[43]]
leftElbowRot = [leftElbowRotStart[0]+frameFraction*(leftElbowRotEnd[0]-leftElbowRotStart[0])]
#print("chestRot=",chestRot) #print("chestRot=",chestRot)
p.setGravity(0,0,0)
kp=1
if (useMotionCapture): if (useMotionCapture):
p.setJointMotorControlMultiDof(humanoid,chest,p.POSITION_CONTROL, targetPosition=chestRot,positionGain=kp, force=maxForce)
p.setJointMotorControlMultiDof(humanoid,neck,p.POSITION_CONTROL,targetPosition=neckRot,positionGain=kp, force=maxForce)
p.setJointMotorControlMultiDof(humanoid,rightHip,p.POSITION_CONTROL,targetPosition=rightHipRot,positionGain=kp, force=maxForce)
p.setJointMotorControlMultiDof(humanoid,rightKnee,p.POSITION_CONTROL,targetPosition=rightKneeRot,positionGain=kp, force=maxForce)
p.setJointMotorControlMultiDof(humanoid,rightAnkle,p.POSITION_CONTROL,targetPosition=rightAnkleRot,positionGain=kp, force=maxForce)
p.setJointMotorControlMultiDof(humanoid,rightShoulder,p.POSITION_CONTROL,targetPosition=rightShoulderRot,positionGain=kp, force=maxForce)
p.setJointMotorControlMultiDof(humanoid,rightElbow, p.POSITION_CONTROL,targetPosition=rightElbowRot,positionGain=kp, force=maxForce)
p.setJointMotorControlMultiDof(humanoid,leftHip, p.POSITION_CONTROL,targetPosition=leftHipRot,positionGain=kp, force=maxForce)
p.setJointMotorControlMultiDof(humanoid,leftKnee, p.POSITION_CONTROL,targetPosition=leftKneeRot,positionGain=kp, force=maxForce)
p.setJointMotorControlMultiDof(humanoid,leftAnkle, p.POSITION_CONTROL,targetPosition=leftAnkleRot,positionGain=kp, force=maxForce)
p.setJointMotorControlMultiDof(humanoid,leftShoulder, p.POSITION_CONTROL,targetPosition=leftShoulderRot,positionGain=kp, force=maxForce)
p.setJointMotorControlMultiDof(humanoid,leftElbow, p.POSITION_CONTROL,targetPosition=leftElbowRot,positionGain=kp, force=maxForce)
if (useMotionCaptureReset):
p.resetJointStateMultiDof(humanoid,chest,chestRot) p.resetJointStateMultiDof(humanoid,chest,chestRot)
p.resetJointStateMultiDof(humanoid,neck,neckRot) p.resetJointStateMultiDof(humanoid,neck,neckRot)
p.resetJointStateMultiDof(humanoid,rightHip,rightHipRot) p.resetJointStateMultiDof(humanoid,rightHip,rightHipRot)
@@ -106,11 +196,5 @@ while (1):
p.resetJointStateMultiDof(humanoid,leftAnkle, leftAnkleRot) p.resetJointStateMultiDof(humanoid,leftAnkle, leftAnkleRot)
p.resetJointStateMultiDof(humanoid,leftShoulder, leftShoulderRot) p.resetJointStateMultiDof(humanoid,leftShoulder, leftShoulderRot)
p.resetJointStateMultiDof(humanoid,leftElbow, leftElbowRot) p.resetJointStateMultiDof(humanoid,leftElbow, leftElbowRot)
else: p.stepSimulation()
for i in range(len(paramIds)): #time.sleep(1./240.)
c = paramIds[i]
targetPos = p.readUserDebugParameter(c)
p.setJointMotorControl2(humanoid,jointIds[i],
p.POSITION_CONTROL,targetPos, force=5*240.)
time.sleep(0.1)

View File

@@ -208,7 +208,7 @@ static int pybullet_internalSetVectord(PyObject* obVec, double vector[3])
return 0; return 0;
} }
// vector - double[3] which will be set by values from obVec // vector - double[4] which will be set by values from obVec
static int pybullet_internalSetVector4d(PyObject* obVec, double vector[4]) static int pybullet_internalSetVector4d(PyObject* obVec, double vector[4])
{ {
int i, len; int i, len;
@@ -1879,6 +1879,7 @@ static PyObject* pybullet_resetSimulation(PyObject* self, PyObject* args, PyObje
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;
} }
//this method is obsolete, use pybullet_setJointMotorControl2 instead //this method is obsolete, use pybullet_setJointMotorControl2 instead
static PyObject* pybullet_setJointMotorControl(PyObject* self, PyObject* args) static PyObject* pybullet_setJointMotorControl(PyObject* self, PyObject* args)
{ {
@@ -2387,6 +2388,180 @@ static PyObject* pybullet_setJointMotorControlArray(PyObject* self, PyObject* ar
// return NULL; // return NULL;
} }
static PyObject* pybullet_setJointMotorControlMultiDof(PyObject* self, PyObject* args, PyObject* keywds)
{
int bodyUniqueId, jointIndex, controlMode;
double targetPositionArray[4] = { 0, 0, 0, 1 };
double targetVelocityArray[3] = { 0, 0, 0 };
int targetPositionSize = 0;
int targetVelocitySize = 0;
PyObject* targetPositionObj = 0;
PyObject* targetVelocityObj = 0;
double force = 100000.0;
double kp = 0.1;
double kd = 1.0;
double maxVelocity = -1;
b3PhysicsClientHandle sm = 0;
int physicsClientId = 0;
static char* kwlist[] = { "bodyUniqueId", "jointIndex", "controlMode", "targetPosition", "targetVelocity", "force", "positionGain", "velocityGain", "maxVelocity", "physicsClientId", NULL };
if (!PyArg_ParseTupleAndKeywords(args, keywds, "iii|OOddddi", kwlist, &bodyUniqueId, &jointIndex, &controlMode,
&targetPositionObj, &targetVelocityObj, &force, &kp, &kd, &maxVelocity, &physicsClientId))
{
return NULL;
}
sm = getPhysicsClient(physicsClientId);
if (sm == 0)
{
PyErr_SetString(SpamError, "Not connected to physics server.");
return NULL;
}
if (targetPositionObj)
{
PyObject* targetPositionSeq = 0;
int i = 0;
targetPositionSeq = PySequence_Fast(targetPositionObj, "expected a targetPosition sequence");
targetPositionSize = PySequence_Size(targetPositionObj);
if (targetPositionSize < 0)
{
targetPositionSize = 0;
}
if (targetPositionSize >4)
{
targetPositionSize = 4;
}
for (i = 0; i < targetPositionSize; i++)
{
targetPositionArray[i] = pybullet_internalGetFloatFromSequence(targetPositionSeq, i);
}
}
if (targetVelocityObj)
{
int i = 0;
PyObject* targetVelocitySeq = 0;
targetVelocitySeq = PySequence_Fast(targetVelocityObj, "expected a targetVelocity sequence");
targetVelocitySize = PySequence_Size(targetVelocityObj);
if (targetVelocitySize < 0)
{
targetVelocitySize = 0;
}
if (targetVelocitySize >3)
{
targetVelocitySize = 3;
}
for (i = 0; i < targetVelocitySize; i++)
{
targetVelocityArray[i] = pybullet_internalGetFloatFromSequence(targetVelocitySeq, i);
}
}
//if (targetPositionSize == 0 && targetVelocitySize == 0)
//{
{
int numJoints;
b3SharedMemoryCommandHandle commandHandle;
b3SharedMemoryStatusHandle statusHandle;
struct b3JointInfo info;
numJoints = b3GetNumJoints(sm, bodyUniqueId);
if ((jointIndex >= numJoints) || (jointIndex < 0))
{
PyErr_SetString(SpamError, "Joint index out-of-range.");
return NULL;
}
if (//(controlMode != CONTROL_MODE_VELOCITY)&&
//(controlMode != CONTROL_MODE_TORQUE) &&
(controlMode != CONTROL_MODE_POSITION_VELOCITY_PD)//&&
//(controlMode != CONTROL_MODE_PD)
)
{
PyErr_SetString(SpamError, "Illegal control mode.");
return NULL;
}
commandHandle = b3JointControlCommandInit2(sm, bodyUniqueId, controlMode);
b3GetJointInfo(sm, bodyUniqueId, jointIndex, &info);
switch (controlMode)
{
#if 0
case CONTROL_MODE_VELOCITY:
{
b3JointControlSetDesiredVelocity(commandHandle, info.m_uIndex,
targetVelocity);
b3JointControlSetKd(commandHandle, info.m_uIndex, kd);
b3JointControlSetMaximumForce(commandHandle, info.m_uIndex, force);
break;
}
case CONTROL_MODE_TORQUE:
{
b3JointControlSetDesiredForceTorque(commandHandle, info.m_uIndex,
force);
break;
}
#endif
case CONTROL_MODE_POSITION_VELOCITY_PD:
case CONTROL_MODE_PD:
{
//make sure size == info.m_qSize
if (maxVelocity > 0)
{
b3JointControlSetMaximumVelocity(commandHandle, info.m_uIndex, maxVelocity);
}
if (info.m_qSize == targetPositionSize)
{
b3JointControlSetDesiredPositionMultiDof(commandHandle, info.m_qIndex,
targetPositionArray, targetPositionSize);
}
else
{
//printf("Warning: targetPosition array size doesn't match joint position size (got %d, expected %d).",targetPositionSize, info.m_qSize);
}
b3JointControlSetKp(commandHandle, info.m_uIndex, kp);
if (info.m_uSize == targetVelocitySize)
{
b3JointControlSetDesiredVelocityMultiDof(commandHandle, info.m_uIndex,
targetVelocityArray, targetVelocitySize);
}
else
{
//printf("Warning: targetVelocity array size doesn't match joint dimentions (got %d, expected %d).", targetVelocitySize, info.m_uSize);
}
b3JointControlSetKd(commandHandle, info.m_uIndex, kd);
b3JointControlSetMaximumForce(commandHandle, info.m_uIndex, force);
break;
}
default:
{
}
};
statusHandle = b3SubmitClientCommandAndWaitStatus(sm, commandHandle);
Py_INCREF(Py_None);
return Py_None;
}
// PyErr_SetString(SpamError, "Error parsing arguments in setJointControl.");
// return NULL;
}
static PyObject* pybullet_setJointMotorControl2(PyObject* self, PyObject* args, PyObject* keywds) static PyObject* pybullet_setJointMotorControl2(PyObject* self, PyObject* args, PyObject* keywds)
{ {
int bodyUniqueId, jointIndex, controlMode; int bodyUniqueId, jointIndex, controlMode;
@@ -3454,14 +3629,13 @@ static PyObject* pybullet_resetJointState(PyObject* self, PyObject* args, PyObje
static PyObject* pybullet_resetJointStateMultiDof(PyObject* self, PyObject* args, PyObject* keywds) static PyObject* pybullet_resetJointStateMultiDof(PyObject* self, PyObject* args, PyObject* keywds)
{ {
{ {
b3PhysicsClientHandle sm = 0;
int bodyUniqueId; int bodyUniqueId;
int jointIndex; int jointIndex;
double targetPositionArray[4] = { 0, 0, 0, 0 }; double targetPositionArray[4] = { 0, 0, 0, 1 };
double targetVelocityArray[3] = { 0, 0, 0 }; double targetVelocityArray[3] = { 0, 0, 0 };
int targetPositionSize = 0; int targetPositionSize = 0;
int targetVelocitySize = 0; int targetVelocitySize = 0;
b3PhysicsClientHandle sm = 0;
PyObject* targetPositionObj = 0; PyObject* targetPositionObj = 0;
PyObject* targetVelocityObj = 0; PyObject* targetVelocityObj = 0;
@@ -8634,6 +8808,56 @@ static PyObject* pybullet_invertTransform(PyObject* self,
return NULL; return NULL;
} }
static PyObject* pybullet_getQuaternionSlerp(PyObject* self, PyObject* args, PyObject* keywds)
{
PyObject* quatStartObj;
PyObject* quatEndObj;
double quatStart[4];
double quatEnd[4];
double interpolationFraction;
int physicsClientId = 0;
int hasQuatStart = 0;
int hasQuatEnd = 0;
static char* kwlist[] = { "quaternionStart", "quaternionEnd", "interpolationFraction", "physicsClientId", NULL };
if (!PyArg_ParseTupleAndKeywords(args, keywds, "OOd|i", kwlist, &quatStartObj, &quatEndObj, &interpolationFraction, &physicsClientId))
{
return NULL;
}
if (quatStartObj)
{
hasQuatStart = pybullet_internalSetVector4d(quatStartObj, quatStart);
}
if (quatEndObj)
{
hasQuatEnd = pybullet_internalSetVector4d(quatEndObj, quatEnd);
}
if (hasQuatStart && hasQuatEnd)
{
double quatOut[4];
b3QuaternionSlerp(quatStart, quatEnd, interpolationFraction, quatOut);
{
PyObject* pylist;
int i;
pylist = PyTuple_New(4);
for (i = 0; i < 4; i++)
PyTuple_SetItem(pylist, i, PyFloat_FromDouble(quatOut[i]));
return pylist;
}
}
else
{
PyErr_SetString(SpamError, "Require start and end quaternion, each with 4 components [x,y,z,w].");
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
/// quaternion <-> euler yaw/pitch/roll convention from URDF/SDF, see Gazebo /// quaternion <-> euler yaw/pitch/roll convention from URDF/SDF, see Gazebo
/// https://github.com/arpg/Gazebo/blob/master/gazebo/math/Quaternion.cc /// https://github.com/arpg/Gazebo/blob/master/gazebo/math/Quaternion.cc
static PyObject* pybullet_getEulerFromQuaternion(PyObject* self, static PyObject* pybullet_getEulerFromQuaternion(PyObject* self,
@@ -9750,6 +9974,11 @@ static PyMethodDef SpamMethods[] = {
"Set a single joint motor control mode and desired target value. There is " "Set a single joint motor control mode and desired target value. There is "
"no immediate state change, stepSimulation will process the motors."}, "no immediate state change, stepSimulation will process the motors."},
{ "setJointMotorControlMultiDof", (PyCFunction)pybullet_setJointMotorControlMultiDof, METH_VARARGS | METH_KEYWORDS,
"Set a single joint motor control mode and desired target value. There is "
"no immediate state change, stepSimulation will process the motors."
"This method sets multi-degree-of-freedom motor such as the spherical joint motor." },
{"setJointMotorControlArray", (PyCFunction)pybullet_setJointMotorControlArray, METH_VARARGS | METH_KEYWORDS, {"setJointMotorControlArray", (PyCFunction)pybullet_setJointMotorControlArray, METH_VARARGS | METH_KEYWORDS,
"Set an array of motors control mode and desired target value. There is " "Set an array of motors control mode and desired target value. There is "
"no immediate state change, stepSimulation will process the motors." "no immediate state change, stepSimulation will process the motors."
@@ -9883,6 +10112,9 @@ static PyMethodDef SpamMethods[] = {
{"getMatrixFromQuaternion", (PyCFunction)pybullet_getMatrixFromQuaternion, METH_VARARGS | METH_KEYWORDS, {"getMatrixFromQuaternion", (PyCFunction)pybullet_getMatrixFromQuaternion, METH_VARARGS | METH_KEYWORDS,
"Compute the 3x3 matrix from a quaternion, as a list of 9 values (row-major)"}, "Compute the 3x3 matrix from a quaternion, as a list of 9 values (row-major)"},
{ "getQuaternionSlerp", (PyCFunction)pybullet_getQuaternionSlerp, METH_VARARGS | METH_KEYWORDS,
"Compute the spherical interpolation given a start and end quaternion and an interpolation value in range [0..1]" },
{"calculateInverseDynamics", (PyCFunction)pybullet_calculateInverseDynamics, METH_VARARGS | METH_KEYWORDS, {"calculateInverseDynamics", (PyCFunction)pybullet_calculateInverseDynamics, METH_VARARGS | METH_KEYWORDS,
"Given an object id, joint positions, joint velocities and joint " "Given an object id, joint positions, joint velocities and joint "
"accelerations, compute the joint forces using Inverse Dynamics"}, "accelerations, compute the joint forces using Inverse Dynamics"},

View File

@@ -317,6 +317,7 @@ sources = ["examples/pybullet/pybullet.c"]\
+["src/BulletDynamics/Featherstone/btMultiBodyMLCPConstraintSolver.cpp"]\ +["src/BulletDynamics/Featherstone/btMultiBodyMLCPConstraintSolver.cpp"]\
+["src/BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.cpp"]\ +["src/BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.cpp"]\
+["src/BulletDynamics/Featherstone/btMultiBodySliderConstraint.cpp"]\ +["src/BulletDynamics/Featherstone/btMultiBodySliderConstraint.cpp"]\
+["src/BulletDynamics/Featherstone/btMultiBodySphericalJointMotor.cpp"]\
+["src/BulletDynamics/Vehicle/btRaycastVehicle.cpp"]\ +["src/BulletDynamics/Vehicle/btRaycastVehicle.cpp"]\
+["src/BulletDynamics/Vehicle/btWheelInfo.cpp"]\ +["src/BulletDynamics/Vehicle/btWheelInfo.cpp"]\
+["src/BulletDynamics/Character/btKinematicCharacterController.cpp"]\ +["src/BulletDynamics/Character/btKinematicCharacterController.cpp"]\

View File

@@ -41,6 +41,7 @@ SET(BulletDynamics_SRCS
Featherstone/btMultiBodyMLCPConstraintSolver.cpp Featherstone/btMultiBodyMLCPConstraintSolver.cpp
Featherstone/btMultiBodyPoint2Point.cpp Featherstone/btMultiBodyPoint2Point.cpp
Featherstone/btMultiBodySliderConstraint.cpp Featherstone/btMultiBodySliderConstraint.cpp
Featherstone/btMultiBodySphericalJointMotor.cpp
MLCPSolvers/btDantzigLCP.cpp MLCPSolvers/btDantzigLCP.cpp
MLCPSolvers/btMLCPSolver.cpp MLCPSolvers/btMLCPSolver.cpp
MLCPSolvers/btLemkeAlgorithm.cpp MLCPSolvers/btLemkeAlgorithm.cpp

View File

@@ -37,9 +37,7 @@ const btScalar SLEEP_EPSILON = btScalar(0.05); // this is a squared velocity (m
const btScalar SLEEP_TIMEOUT = btScalar(2); // in seconds const btScalar SLEEP_TIMEOUT = btScalar(2); // in seconds
} // namespace } // namespace
namespace void btMultiBody::spatialTransform(const btMatrix3x3 &rotation_matrix, // rotates vectors in 'from' frame to vectors in 'to' frame
{
void SpatialTransform(const btMatrix3x3 &rotation_matrix, // rotates vectors in 'from' frame to vectors in 'to' frame
const btVector3 &displacement, // vector from origin of 'from' frame to origin of 'to' frame, in 'to' coordinates const btVector3 &displacement, // vector from origin of 'from' frame to origin of 'to' frame, in 'to' coordinates
const btVector3 &top_in, // top part of input vector const btVector3 &top_in, // top part of input vector
const btVector3 &bottom_in, // bottom part of input vector const btVector3 &bottom_in, // bottom part of input vector
@@ -50,6 +48,10 @@ void SpatialTransform(const btMatrix3x3 &rotation_matrix, // rotates vectors in
bottom_out = -displacement.cross(top_out) + rotation_matrix * bottom_in; bottom_out = -displacement.cross(top_out) + rotation_matrix * bottom_in;
} }
namespace
{
#if 0 #if 0
void InverseSpatialTransform(const btMatrix3x3 &rotation_matrix, void InverseSpatialTransform(const btMatrix3x3 &rotation_matrix,
const btVector3 &displacement, const btVector3 &displacement,
@@ -330,6 +332,9 @@ void btMultiBody::setupPlanar(int i,
m_links[i].updateCacheMultiDof(); m_links[i].updateCacheMultiDof();
// //
updateLinksDofOffsets(); updateLinksDofOffsets();
m_links[i].setAxisBottom(1, m_links[i].getAxisBottom(1).normalized());
m_links[i].setAxisBottom(2, m_links[i].getAxisBottom(2).normalized());
} }
void btMultiBody::finalizeMultiDof() void btMultiBody::finalizeMultiDof()
@@ -540,35 +545,26 @@ void btMultiBody::compTreeLinkVelocities(btVector3 *omega, btVector3 *vel) const
{ {
int num_links = getNumLinks(); int num_links = getNumLinks();
// Calculates the velocities of each link (and the base) in its local frame // Calculates the velocities of each link (and the base) in its local frame
omega[0] = quatRotate(m_baseQuat, getBaseOmega()); const btQuaternion& base_rot = getWorldToBaseRot();
vel[0] = quatRotate(m_baseQuat, getBaseVel()); omega[0] = quatRotate(base_rot, getBaseOmega());
vel[0] = quatRotate(base_rot, getBaseVel());
for (int i = 0; i < num_links; ++i) for (int i = 0; i < num_links; ++i)
{ {
const int parent = m_links[i].m_parent; const btMultibodyLink& link = getLink(i);
const int parent = link.m_parent;
// transform parent vel into this frame, store in omega[i+1], vel[i+1] // transform parent vel into this frame, store in omega[i+1], vel[i+1]
SpatialTransform(btMatrix3x3(m_links[i].m_cachedRotParentToThis), m_links[i].m_cachedRVector, spatialTransform(btMatrix3x3(link.m_cachedRotParentToThis), link.m_cachedRVector,
omega[parent + 1], vel[parent + 1], omega[parent + 1], vel[parent + 1],
omega[i + 1], vel[i + 1]); omega[i + 1], vel[i + 1]);
// now add qidot * shat_i // now add qidot * shat_i
//only supported for revolute/prismatic joints, todo: spherical and planar joints const btScalar* jointVel = getJointVelMultiDof(i);
switch (m_links[i].m_jointType) for (int dof = 0; dof < link.m_dofCount; ++dof)
{ {
case btMultibodyLink::ePrismatic: omega[i + 1] += jointVel[dof] * link.getAxisTop(dof);
case btMultibodyLink::eRevolute: vel[i + 1] += jointVel[dof] * link.getAxisBottom(dof);
{
btVector3 axisTop = m_links[i].getAxisTop(0);
btVector3 axisBottom = m_links[i].getAxisBottom(0);
btScalar jointVel = getJointVel(i);
omega[i + 1] += jointVel * axisTop;
vel[i + 1] += jointVel * axisBottom;
break;
}
default:
{
}
} }
} }
} }

View File

@@ -600,6 +600,15 @@ public:
m_userIndex2 = index; m_userIndex2 = index;
} }
static void spatialTransform(const btMatrix3x3 &rotation_matrix, // rotates vectors in 'from' frame to vectors in 'to' frame
const btVector3 &displacement, // vector from origin of 'from' frame to origin of 'to' frame, in 'to' coordinates
const btVector3 &top_in, // top part of input vector
const btVector3 &bottom_in, // bottom part of input vector
btVector3 &top_out, // top part of output vector
btVector3 &bottom_out); // bottom part of output vector
private: private:
btMultiBody(const btMultiBody &); // not implemented btMultiBody(const btMultiBody &); // not implemented
void operator=(const btMultiBody &); // not implemented void operator=(const btMultiBody &); // not implemented

View File

@@ -0,0 +1,172 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2018 Erwin Coumans http://bulletphysics.org
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///This file was written by Erwin Coumans
#include "btMultiBodySphericalJointMotor.h"
#include "btMultiBody.h"
#include "btMultiBodyLinkCollider.h"
#include "BulletCollision/CollisionDispatch/btCollisionObject.h"
#include "LinearMath/btTransformUtil.h"
#include "BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.h"
btMultiBodySphericalJointMotor::btMultiBodySphericalJointMotor(btMultiBody* body, int link, btScalar maxMotorImpulse)
: btMultiBodyConstraint(body, body, link, body->getLink(link).m_parent, 3, true),
m_desiredVelocity(0, 0, 0),
m_desiredPosition(0,0,0,1),
m_kd(1.),
m_kp(0.2),
m_erp(1),
m_rhsClamp(SIMD_INFINITY)
{
m_maxAppliedImpulse = maxMotorImpulse;
}
void btMultiBodySphericalJointMotor::finalizeMultiDof()
{
allocateJacobiansMultiDof();
// note: we rely on the fact that data.m_jacobians are
// always initialized to zero by the Constraint ctor
int linkDoF = 0;
unsigned int offset = 6 + (m_bodyA->getLink(m_linkA).m_dofOffset + linkDoF);
// row 0: the lower bound
// row 0: the lower bound
jacobianA(0)[offset] = 1;
m_numDofsFinalized = m_jacSizeBoth;
}
btMultiBodySphericalJointMotor::~btMultiBodySphericalJointMotor()
{
}
int btMultiBodySphericalJointMotor::getIslandIdA() const
{
if (this->m_linkA < 0)
{
btMultiBodyLinkCollider* col = m_bodyA->getBaseCollider();
if (col)
return col->getIslandTag();
}
else
{
if (m_bodyA->getLink(m_linkA).m_collider)
{
return m_bodyA->getLink(m_linkA).m_collider->getIslandTag();
}
}
return -1;
}
int btMultiBodySphericalJointMotor::getIslandIdB() const
{
if (m_linkB < 0)
{
btMultiBodyLinkCollider* col = m_bodyB->getBaseCollider();
if (col)
return col->getIslandTag();
}
else
{
if (m_bodyB->getLink(m_linkB).m_collider)
{
return m_bodyB->getLink(m_linkB).m_collider->getIslandTag();
}
}
return -1;
}
void btMultiBodySphericalJointMotor::createConstraintRows(btMultiBodyConstraintArray& constraintRows,
btMultiBodyJacobianData& data,
const btContactSolverInfo& infoGlobal)
{
// only positions need to be updated -- data.m_jacobians and force
// directions were set in the ctor and never change.
if (m_numDofsFinalized != m_jacSizeBoth)
{
finalizeMultiDof();
}
//don't crash
if (m_numDofsFinalized != m_jacSizeBoth)
return;
if (m_maxAppliedImpulse == 0.f)
return;
const btScalar posError = 0;
const btVector3 dummy(0, 0, 0);
btVector3 axis[3] = { btVector3(1, 0, 0), btVector3(0, 1, 0), btVector3(0, 0, 1) };
btQuaternion desiredQuat = m_desiredPosition;
btQuaternion currentQuat(m_bodyA->getJointPosMultiDof(m_linkA)[0],
m_bodyA->getJointPosMultiDof(m_linkA)[1],
m_bodyA->getJointPosMultiDof(m_linkA)[2],
m_bodyA->getJointPosMultiDof(m_linkA)[3]);
btQuaternion relRot = currentQuat.inverse() * desiredQuat;
btVector3 angleDiff;
btGeneric6DofSpring2Constraint::matrixToEulerXYZ(btMatrix3x3(relRot), angleDiff);
for (int row = 0; row < getNumRows(); row++)
{
btMultiBodySolverConstraint& constraintRow = constraintRows.expandNonInitializing();
int dof = row;
btScalar currentVelocity = m_bodyA->getJointVelMultiDof(m_linkA)[dof];
btScalar desiredVelocity = this->m_desiredVelocity[row];
btScalar velocityError = desiredVelocity - currentVelocity;
btMatrix3x3 frameAworld;
frameAworld.setIdentity();
frameAworld = m_bodyA->localFrameToWorld(m_linkA, frameAworld);
btScalar posError = 0;
{
btAssert(m_bodyA->getLink(m_linkA).m_jointType == btMultibodyLink::eSpherical);
switch (m_bodyA->getLink(m_linkA).m_jointType)
{
case btMultibodyLink::eSpherical:
{
btVector3 constraintNormalAng = frameAworld.getColumn(row % 3);
posError = m_kp*angleDiff[row % 3];
fillMultiBodyConstraint(constraintRow, data, 0, 0, constraintNormalAng,
btVector3(0,0,0), dummy, dummy,
posError,
infoGlobal,
-m_maxAppliedImpulse, m_maxAppliedImpulse, true);
constraintRow.m_orgConstraint = this;
constraintRow.m_orgDofIndex = row;
break;
}
default:
{
btAssert(0);
}
};
}
}
}

View File

@@ -0,0 +1,77 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2018 Erwin Coumans http://bulletphysics.org
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///This file was written by Erwin Coumans
#ifndef BT_MULTIBODY_SPHERICAL_JOINT_MOTOR_H
#define BT_MULTIBODY_SPHERICAL_JOINT_MOTOR_H
#include "btMultiBodyConstraint.h"
struct btSolverInfo;
class btMultiBodySphericalJointMotor : public btMultiBodyConstraint
{
protected:
btVector3 m_desiredVelocity;
btQuaternion m_desiredPosition;
btScalar m_kd;
btScalar m_kp;
btScalar m_erp;
btScalar m_rhsClamp; //maximum error
public:
btMultiBodySphericalJointMotor(btMultiBody* body, int link, btScalar maxMotorImpulse);
virtual ~btMultiBodySphericalJointMotor();
virtual void finalizeMultiDof();
virtual int getIslandIdA() const;
virtual int getIslandIdB() const;
virtual void createConstraintRows(btMultiBodyConstraintArray& constraintRows,
btMultiBodyJacobianData& data,
const btContactSolverInfo& infoGlobal);
virtual void setVelocityTarget(const btVector3& velTarget, btScalar kd = 1.f)
{
m_desiredVelocity = velTarget;
m_kd = kd;
}
virtual void setPositionTarget(const btQuaternion& posTarget, btScalar kp = 1.f)
{
m_desiredPosition = posTarget;
m_kp = kp;
}
virtual void setErp(btScalar erp)
{
m_erp = erp;
}
virtual btScalar getErp() const
{
return m_erp;
}
virtual void setRhsClamp(btScalar rhsClamp)
{
m_rhsClamp = rhsClamp;
}
virtual void debugDraw(class btIDebugDraw* drawer)
{
//todo(erwincoumans)
}
};
#endif //BT_MULTIBODY_SPHERICAL_JOINT_MOTOR_H