28. Surface Velocity Conveyor Belt

The class agx::SurfaceVelocityConveyorBelt can be used in order to simulate a basic conveyor belt. No internal mechanics in the conveyor belt are simulated, only velocity changes in contacts between conveyor belt and transported goods. As the name indicates, the SurfaceVelocityConveyorBelt uses the surface velocity property inherent in contact points, which is described in chapter 11.7.6. For simple cases, if might suffice to use an agxCollide::Geometry’s surface velocity. However, the latter is constant over the whole surface of the Geometry. For cases like in a conveyor belt, one wants the velocity to follow around the surface of the geometry which might be more complex (going up and down, …).

A SurfaceVelocityConveyorBelt has different surface velocity directions for different parts of the belt, but the length - or rather “speed” - remains the same. The different directions are computed from a list of points along the surface of the belt in direction of its movement - the single directions are computed from one point to the next. For a given contact point, the closest line segment from one conveyor belt point to the next is chosen for the surface velocity. This might give wrong behavior in more advanced concave cases, which is a limitation of the model. For “typical” conveyor belt cases however, it should work fine.

../_images/surface_velocity_conveyor_belt_1.png

Fig. 28.1 Two conveyor belts. Ret dots are points, yellow lines indicate direction.

Implementationwise, the agx::SurfaceVelocityConveyorBelt inherits from agxCollide::Geometry and can be used as a geometry. It is constructed from a list of points, such as in the following example:

#include <agx/SurfaceVelocityConveyorBelt.h>

void createConveyorBelt(agxSDK::Simulation* sim)
{
  agx::Vec3Vector points;
  points.push_back(agx::Vec3(-1, 0, 0));
  points.push_back(agx::Vec3(0, 0, 1));
  points.push_back(agx::Vec3(1, 0, 0)); // Change in direction, from upwards to downwards.
  agx::SurfaceVelocityConveyorBeltRef belt = new agx::SurfaceVelocityConveyorBelt(points);
  sim->add(belt);
  // We should also add shapes to the conveyor belt, and they should map the points.
}

Given n points, the surface velocity conveyor belt will create n-1 directions. This allows for open connection. If a closed loop is desired, then the first point should be added another time as the last one, as in this example:

points.push_back(a);
points.push_back(b);
points.push_back(c);
points.push_back(d);
points.push_back(a); // Close the rectangle loop.

The speed of a conveyor belt can be set by a call to void setSpeed(agx::Real speed), where negative speeds will indicate a change in direction.

Debug rendering can be activated for a conveyor belt by a call to bool enableDebugRendering(agxSDK::Simulation* sim) (and disabled with a call to bool disableDebugRendering()). It will look like the red dots and yellow lines in Fig. 28.1.

When creating an agx::SurfaceVelocityConveyorBelt for an agxCollide::Trimesh, one can cut the trimesh with a plane in order to obtain an ordered list of points. This list of points can be used as input to the constructor for the conveyor belt, instead of having to specify them all by hand. However, to close the loop, the points’ first point should be added once more as its last, as in this example:

#include <agxCollide/Trimesh.h>
#include <agx/SurfaceVelocityConveyorBelt.h>

agx::SurfaceVelocityConveyorBelt* createConveyorBeltFromTrimesh(agxCollide::TrimeshRef trimesh)
{
  auto plane = agx::Plane(agx::Vec3(0, 1, 0), 0);
  // This will increase and decrease the trimesh's ref count - make sure you have a ref pointer to it.
  auto points = agxCollide::intersectTrimeshWithPlane(trimesh, plane, agx::AffineMatrix4x4::translate(trimesh->getCenter()));
  if (points.size() == 0)
    return nullptr;
  points.push_back(points.front()); // Close the loop.
  auto belt = new agx::SurfaceVelocityConveyorBelt(points);
  belt->add(trimesh);
  return belt;
}