Page 1 of 1

[Bepu2] Belt conveyor

Posted: Tue Jun 11, 2019 3:39 pm
by Darkon76
Hello,

I’m trying to create a conveyor belt. I added another struct to the body ConveyorSettings,.
At the IntegrateBodiesAndUpdateBoundingBoxes, it sets the velocity.Linear before the PoseIntegration.Integrate most of the time 0 because the conveyor isn’t moving, then set the conveyor velocity to the velocity.Linear to simulate the belt velocity, propagating the movement to other objects. It works but it has a problem, if the conveyor is carrying an object and the belt stop moving the payload will stop and after short amount of time the payload will sleep. If the belt is restarted the payload wouldn’t be affected because it is sleeping.

Is there a better way to implement the conveyor?

For performance it is good that the payload sleeps. Because the payload is sleeping I can’t use collision detection to wake them. What other option do I have to wake up the payload?


Kind Regards

Image

Code: Select all

  unsafe void IntegrateBodiesAndUpdateBoundingBoxes(int startIndex, int endIndex, float dt, ref BoundingBoxBatcher boundingBoxBatcher, int workerIndex)
        {
		…
            ref var baseConveyorSettings = ref bodies.ActiveSet.ConveyorSettings[0];
            for (int i = startIndex; i < endIndex; ++i)
            {
                ref var pose = ref Unsafe.Add(ref basePoses, i);
                ref var velocity = ref Unsafe.Add(ref baseVelocities, i);
                ref var conveyorSettings = ref Unsafe.Add(ref baseConveyorSettings, i);


                if (conveyorSettings.IsLinearConveyor)
                {
                    velocity.Linear = conveyorSettings.LinearVelocity;
                }

                var previousOrientation = pose.Orientation; //This is unused if conservation of angular momentum is disabled... compiler *may* remove it...

                PoseIntegration.Integrate(pose, velocity, dt, out pose);
		…
                inertia.InverseMass = localInertia.InverseMass;

                if (conveyorSettings.IsLinearConveyor)
                {
                    velocity.Linear = conveyorSettings.LinearVelocity + conveyorSettings.ConveyorVelocity;
                }
                ...

Note the conveyor is easily implemented in bepu 1 adding an offset at EntityBase-> void IPositionUpdateable.PreUpdatePosition(float dt)

Code: Select all

            if (PositionUpdateMode == PositionUpdateMode.Discrete)
            {
                var velocity = IsLinearConveyor ? linearVelocity - LinearOffset : linearVelocity;

Re: [Bepu2] Belt conveyor

Posted: Tue Jun 11, 2019 10:34 pm
by Norbo
Any time the conveyor restarts, you could use Simulation.Awakener.AwakenBody to force it awake. Any bodies on the conveyor will be forced awake with it.

By the way, unless the majority of bodies are conveyor belts, it would probably be simpler and faster to directly modify velocity and pose of the conveyor outside of the pose integrator. You can do this external to the timestep or attach a callback to one of the timestepper stages, like PositionFirstTimeStepper.BeforeCollisionDetection. (An ITimestepper is provided in the Simulation.Create; by default it uses a PositionFirstTimeStepper. You could supply a PositionLastTimeStepper, SubsteppingTimestepper, or your own implementation too.)

Re: [Bepu2] Belt conveyor

Posted: Tue Jun 11, 2019 10:59 pm
by Darkon76
Thanks for the replay.

After a lot of tries it ended being a mix of awake and shake the conveyor.

So you recommend at the before collision detection set the velocity and at PositionlasttimeStepper set the correct position of the conveyor to avoid the movement.

Re: [Bepu2] Belt conveyor

Posted: Tue Jun 11, 2019 11:30 pm
by Norbo
You could do both pose and velocity in PositionFirstTimestepper.BeforeCollisionDetection. In the PositionFirstTimestepper, velocities and poses are integrated up front, so if you set the pose there it'll stick until the next frame.

If using the PositionLastTimestepper instead of the PositionFirstTimestepper, velocities are integrated early and poses late. Presumably the conveyors are kinematic and the pose integrator callback you provided doesn't apply velocity changes to kinematics, so you could just make the velocity and pose modification before or after the simulation timestep without using any stage callbacks.

Re: [Bepu2] Belt conveyor

Posted: Thu Jun 13, 2019 5:04 pm
by Darkon76
A custom TimeStepper worked like a charm. It moves the payload and also it doesn't have the sleep problem.

Thanks for the help.

This is my custom unoptimized code (I know that I should have a collection with only the conveyors)

Code: Select all

        public void Timestep(Simulation simulation, float dt, IThreadDispatcher threadDispatcher = null)
        {
            simulation.Sleep(threadDispatcher);
            Slept?.Invoke(dt, threadDispatcher);

            simulation.IntegrateVelocitiesBoundsAndInertias(dt, threadDispatcher);
            BeforeCollisionDetection?.Invoke(dt, threadDispatcher);

            simulation.CollisionDetection(dt, threadDispatcher);
            CollisionsDetected?.Invoke(dt, threadDispatcher);


            int count = simulation.Bodies.ActiveSet.Count;
            ref var baseConveyorSettings = ref simulation.Bodies.ActiveSet.ConveyorSettings[0];
            ref var baseVelocities = ref simulation.Bodies.ActiveSet.Velocities[0];

            for (int i = 0; i < count; i++)
            {
                ref var conveyorSettings = ref Unsafe.Add(ref baseConveyorSettings, i);
                ref var velocity = ref Unsafe.Add(ref baseVelocities, i);
                if (conveyorSettings.IsLinearConveyor)
                {
                    velocity.Linear = conveyorSettings.LinearVelocity + conveyorSettings.ConveyorVelocity;
                }
            }
            


            simulation.Solve(dt, threadDispatcher);
            ConstraintsSolved?.Invoke(dt, threadDispatcher);


            for (int i = 0; i < count; i++)
            {
                ref var conveyorSettings = ref Unsafe.Add(ref baseConveyorSettings, i);
                ref var velocity = ref Unsafe.Add(ref baseVelocities, i);
                if (conveyorSettings.IsLinearConveyor)
                {
                    velocity.Linear = conveyorSettings.LinearVelocity;
                }
            }

            simulation.IntegratePoses(dt, threadDispatcher);
            PosesIntegrated?.Invoke(dt, threadDispatcher);

            simulation.IncrementallyOptimizeDataStructures(threadDispatcher);
        }