def run(self): # Return immediately if no resets are required. if self.period == -1: return # Establish connection to Azrael. client = azrael.client.Client() # Query all objects in the scene. These are the only objects that will # survive the reset. ret = client.getAllObjectIDs() assert ret.ok ret = client.getRigidBodies(ret.data) assert ret.ok allowed_objIDs = {k: v["rbs"] for k, v in ret.data.items() if v is not None} print("Took simulation snapshot for reset: ({} objects)".format(len(allowed_objIDs))) # Periodically reset the SV values. Set them several times because it # is well possible that not all State Variables reach Leonard in the # same frame, which means some objects will be reset while other are # not. This in turn may cause strange artefacts in the next physics # update step, especially when the objects now partially overlap. while True: # Wait until the timeout expires. time.sleep(self.period) # Remove all newly added objects. ret = client.getAllObjectIDs() for objID in ret.data: if objID not in allowed_objIDs: client.removeObject(objID) # Forcefully reset the position and velocity of every object. Do # this several times since network latency may result in some # objects being reset sooner than others. for ii in range(5): for objID, SV in allowed_objIDs.items(): tmp = { "position": SV.position, "velocityLin": SV.velocityLin, "velocityRot": SV.velocityRot, "rotation": SV.rotation, } assert client.setRigidBodies({objID: tmp}).ok time.sleep(0.1)
def placeTarget(host, numTargets=1): """ Spawn ``numTargets`` in the scene. The targets visually oscillate in size. They also have no collision shapes and are thus unaffected by physics (ie they cannot collide with anything). """ # Connect to Azrael. client = azrael.client.Client(ip=host) # Spawn the target object from the 'BoosterCube_1' template (defined in # 'demo_boostercube' that must already be running at this point). init = [] for ii in range(numTargets): tmp = { 'templateID': 'BoosterCube_1', 'rbs': {'imass': 0, 'position': (0, 0, 3 * ii)} } init.append(tmp) ret = client.spawn(init) # Check for errors and abort if there are any. if not ret.ok: print(ret) sys.exit(1) # Extract the IDs of the spawned target objects. targetIDs = ret.data print('Spawned {} targets'.format(len(targetIDs))) del init, ret # Replace the collision shape with an empty one to disable the physics for # those targets. cs = types.CollShapeEmpty() cs = types.CollShapeMeta('empty', (0, 0, 0), (0, 0, 0, 1), cs) cmd = {targetID: {'cshapes': {'cssphere': cs}} for targetID in targetIDs} assert client.setRigidBodies(cmd).ok del cs # Tag the object with target. This is necessary because the # `PyConBrisbaneClient.selectNewTarget` method will use to distinguish # targets from other objects. cmd = {targetID: 'Target' for targetID in targetIDs} assert client.setCustomData(cmd) # Create a random phase offset in the oscillation pattern (pure eye candy # to avoid all targets scale synchronously). phi = 2 * np.pi * np.random.rand(len(targetIDs)) # Modify the scale of the target every 100ms. cnt = 0 while True: time.sleep(0.1) # Compile the payload for the update command, then send it to Azrael. # The fragment names (eg 'frag_1') are hard coded in the Template # (don't worry about them, just accept that they exist). cmd = {} for idx, targetID in enumerate(targetIDs): # Compute the new scale value. scale = 1 + np.sin(2 * np.pi * 0.1 * cnt + phi[idx]) scale *= 0.1 tmp = { 'frag_1': {'scale': scale}, 'frag_2': {'scale': scale}, } cmd[targetID] = tmp assert client.setFragments(cmd).ok # Randomly update the target's position every 10s. if (cnt % 100) == 0: cmd = {} for targetID in targetIDs: pos = 15 * np.random.rand(3) - 10 cmd[targetID] = {'position': pos.tolist()} assert client.setRigidBodies(cmd).ok cnt += 1