diff --git a/.travis.yml b/.travis.yml index d2ad176f4..b3c3f108b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,9 +10,15 @@ addons: packages: - python3 + script: - echo "CXX="$CXX - echo "CC="$CC + - if [ "$CXX" = "g++" ]; then sudo apt-get install python3-pip; fi + - if [ "$CXX" = "g++" ]; then sudo pip3 install -U pip wheel; fi + - if [ "$CXX" = "g++" ]; then sudo pip3 install setuptools; fi + - if [ "$CXX" = "g++" ]; then sudo python3 setup.py install; fi + - if [ "$CXX" = "g++" ]; then python3 examples/pybullet/unittests/unittests.py --verbose; fi - cmake . -DBUILD_PYBULLET=ON -G"Unix Makefiles" #-DCMAKE_CXX_FLAGS=-Werror - make -j8 - ctest -j8 --output-on-failure diff --git a/examples/SharedMemory/PhysicsServerCommandProcessor.cpp b/examples/SharedMemory/PhysicsServerCommandProcessor.cpp index 45ccf3196..c943a360c 100644 --- a/examples/SharedMemory/PhysicsServerCommandProcessor.cpp +++ b/examples/SharedMemory/PhysicsServerCommandProcessor.cpp @@ -6201,6 +6201,16 @@ bool PhysicsServerCommandProcessor::processSendPhysicsParametersCommand(const st BT_PROFILE("CMD_SEND_PHYSICS_SIMULATION_PARAMETERS"); + if (clientCmd.m_updateFlags & SIM_PARAM_ENABLE_CONE_FRICTION) + { + if (clientCmd.m_physSimParamArgs.m_enableConeFriction) + { + m_data->m_dynamicsWorld->getSolverInfo().m_solverMode &=~SOLVER_DISABLE_IMPLICIT_CONE_FRICTION; + } else + { + m_data->m_dynamicsWorld->getSolverInfo().m_solverMode |=SOLVER_DISABLE_IMPLICIT_CONE_FRICTION; + } + } if (clientCmd.m_updateFlags&SIM_PARAM_UPDATE_DELTA_TIME) { m_data->m_physicsDeltaTime = clientCmd.m_physSimParamArgs.m_deltaTime; diff --git a/examples/SharedMemory/SharedMemoryCommands.h b/examples/SharedMemory/SharedMemoryCommands.h index c16733e45..b3d8d8c49 100644 --- a/examples/SharedMemory/SharedMemoryCommands.h +++ b/examples/SharedMemory/SharedMemoryCommands.h @@ -394,6 +394,8 @@ enum EnumSimDesiredStateUpdateFlags }; + + enum EnumSimParamUpdateFlags { SIM_PARAM_UPDATE_DELTA_TIME=1, @@ -407,7 +409,7 @@ enum EnumSimParamUpdateFlags SIM_PARAM_UPDATE_SPLIT_IMPULSE_PENETRATION_THRESHOLD = 256, SIM_PARAM_UPDATE_COLLISION_FILTER_MODE=512, SIM_PARAM_UPDATE_CONTACT_BREAKING_THRESHOLD = 1024, - SIM_PARAM_MAX_CMD_PER_1MS = 2048, + SIM_PARAM_ENABLE_CONE_FRICTION = 2048, SIM_PARAM_ENABLE_FILE_CACHING = 4096, SIM_PARAM_UPDATE_RESTITUTION_VELOCITY_THRESHOLD = 8192, SIM_PARAM_UPDATE_DEFAULT_NON_CONTACT_ERP=16384, diff --git a/examples/SharedMemory/SharedMemoryPublic.h b/examples/SharedMemory/SharedMemoryPublic.h index b3e1b779f..a7e128e62 100644 --- a/examples/SharedMemory/SharedMemoryPublic.h +++ b/examples/SharedMemory/SharedMemoryPublic.h @@ -692,6 +692,7 @@ struct b3PhysicsSimulationParameters double m_restitutionVelocityThreshold; double m_defaultNonContactERP; double m_frictionERP; + int m_enableConeFriction; }; diff --git a/examples/pybullet/pybullet.c b/examples/pybullet/pybullet.c index 71526de92..bde55bce6 100644 --- a/examples/pybullet/pybullet.c +++ b/examples/pybullet/pybullet.c @@ -1,4 +1,3 @@ - #include "../SharedMemory/PhysicsClientC_API.h" #include "../SharedMemory/PhysicsDirectC_API.h" #include "../SharedMemory/SharedMemoryInProcessPhysicsC_API.h" diff --git a/examples/pybullet/unittests/unittests.py b/examples/pybullet/unittests/unittests.py new file mode 100644 index 000000000..3975c44af --- /dev/null +++ b/examples/pybullet/unittests/unittests.py @@ -0,0 +1,46 @@ +import unittest +import pybullet +import time + +class TestPybulletMethods(unittest.TestCase): + + def test_import(self): + import pybullet as p + self.assertGreater(p.getAPIVersion(), 201700000) + + def test_connect_direct(self): + import pybullet as p + cid = p.connect(p.DIRECT) + self.assertEqual(cid,0) + p.disconnect() + + def test_loadurdf(self): + import pybullet as p + p.connect(p.DIRECT) + ob = p.loadURDF("r2d2.urdf") + self.assertEqual(ob,0) + p.disconnect() + + def test_rolling_friction(self): + import pybullet as p + p.connect(p.DIRECT) + p.loadURDF("plane.urdf") + sphere = p.loadURDF("sphere2.urdf",[0,0,1]) + p.resetBaseVelocity(sphere,linearVelocity=[1,0,0]) + p.changeDynamics(sphere,-1,linearDamping=0,angularDamping=0) + #p.changeDynamics(sphere,-1,rollingFriction=0) + p.setGravity(0,0,-10) + for i in range (1000): + p.stepSimulation() + vel = p.getBaseVelocity(sphere) + self.assertLess(vel[0][0],1e-10) + self.assertLess(vel[0][1],1e-10) + self.assertLess(vel[0][2],1e-10) + self.assertLess(vel[1][0],1e-10) + self.assertLess(vel[1][1],1e-10) + self.assertLess(vel[1][2],1e-10) + p.disconnect() + +if __name__ == '__main__': + unittest.main() + diff --git a/setup.py b/setup.py index f8faa2d37..e86b79fc3 100644 --- a/setup.py +++ b/setup.py @@ -442,7 +442,7 @@ print("-----") setup( name = 'pybullet', - version='1.7.3', + version='1.7.4', description='Official Python Interface for the Bullet Physics SDK specialized for Robotics Simulation and Reinforcement Learning', long_description='pybullet is an easy to use Python module for physics simulation, robotics and deep reinforcement learning based on the Bullet Physics SDK. With pybullet you can load articulated bodies from URDF, SDF and other file formats. pybullet provides forward dynamics simulation, inverse dynamics computation, forward and inverse kinematics and collision detection and ray intersection queries. Aside from physics simulation, pybullet supports to rendering, with a CPU renderer and OpenGL visualization and support for virtual reality headsets.', url='https://github.com/bulletphysics/bullet3', diff --git a/src/BulletDynamics/ConstraintSolver/btContactSolverInfo.h b/src/BulletDynamics/ConstraintSolver/btContactSolverInfo.h index 28d0c1dd4..93865cbc5 100644 --- a/src/BulletDynamics/ConstraintSolver/btContactSolverInfo.h +++ b/src/BulletDynamics/ConstraintSolver/btContactSolverInfo.h @@ -29,7 +29,8 @@ enum btSolverMode SOLVER_CACHE_FRIENDLY = 128, SOLVER_SIMD = 256, SOLVER_INTERLEAVE_CONTACT_AND_FRICTION_CONSTRAINTS = 512, - SOLVER_ALLOW_ZERO_LENGTH_FRICTION_DIRECTIONS = 1024 + SOLVER_ALLOW_ZERO_LENGTH_FRICTION_DIRECTIONS = 1024, + SOLVER_DISABLE_IMPLICIT_CONE_FRICTION = 2048 }; struct btContactSolverInfoData diff --git a/src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.cpp b/src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.cpp index 7d8d21ef7..3f3a73153 100644 --- a/src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.cpp +++ b/src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.cpp @@ -78,7 +78,7 @@ btScalar btMultiBodyConstraintSolver::solveSingleIteration(int iteration, btColl btMultiBodySolverConstraint& frictionConstraint = m_multiBodyLateralFrictionContactConstraints[index]; btScalar totalImpulse = m_multiBodyNormalContactConstraints[frictionConstraint.m_frictionIndex].m_appliedImpulse; - if (infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS) + if (infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS && ((infoGlobal.m_solverMode&SOLVER_DISABLE_IMPLICIT_CONE_FRICTION)==0)) { j1++; int index2 = j1;//iteration&1? j1 : m_multiBodyFrictionContactConstraints.size()-1-j1; @@ -91,7 +91,11 @@ btScalar btMultiBodyConstraintSolver::solveSingleIteration(int iteration, btColl frictionConstraint.m_upperLimit = frictionConstraint.m_friction*totalImpulse; frictionConstraintB.m_lowerLimit = -(frictionConstraintB.m_friction*totalImpulse); frictionConstraintB.m_upperLimit = frictionConstraintB.m_friction*totalImpulse; - resolveConeFrictionConstraintRows(frictionConstraint,frictionConstraintB); + leastSquaredResidual += resolveConeFrictionConstraintRows(frictionConstraint,frictionConstraintB); + if(frictionConstraint.m_multiBodyA) + frictionConstraint.m_multiBodyA->setPosUpdated(false); + if(frictionConstraint.m_multiBodyB) + frictionConstraint.m_multiBodyB->setPosUpdated(false); } } else @@ -112,6 +116,30 @@ btScalar btMultiBodyConstraintSolver::solveSingleIteration(int iteration, btColl } } } + + for (int j1=0;j1m_multiBodyTorsionalFrictionContactConstraints.size();j1++) + { + if (iteration < infoGlobal.m_numIterations) + { + int index = j1;//iteration&1? j1 : m_multiBodyFrictionContactConstraints.size()-1-j1; + + btMultiBodySolverConstraint& frictionConstraint = m_multiBodyTorsionalFrictionContactConstraints[index]; + btScalar totalImpulse = m_multiBodyNormalContactConstraints[frictionConstraint.m_frictionIndex].m_appliedImpulse; + //adjust friction limits here + if (totalImpulse>btScalar(0)) + { + frictionConstraint.m_lowerLimit = -(frictionConstraint.m_friction*totalImpulse); + frictionConstraint.m_upperLimit = frictionConstraint.m_friction*totalImpulse; + btScalar residual = resolveSingleConstraintRowGeneric(frictionConstraint); + leastSquaredResidual += residual*residual; + + if(frictionConstraint.m_multiBodyA) + frictionConstraint.m_multiBodyA->setPosUpdated(false); + if(frictionConstraint.m_multiBodyB) + frictionConstraint.m_multiBodyB->setPosUpdated(false); + } + } + } return leastSquaredResidual; }