All Downloads are FREE. Search and download functionalities are using the official Maven repository.

us.ihmc.javafx.JavaFXRobotVisualizer Maven / Gradle / Ivy

The newest version!
package us.ihmc.javafx;

import java.util.concurrent.atomic.AtomicReference;
import java.util.function.ToDoubleFunction;
import java.util.zip.CRC32;

import controller_msgs.msg.dds.RobotConfigurationData;
import javafx.animation.AnimationTimer;
import javafx.scene.Group;
import javafx.scene.Node;
import us.ihmc.euclid.orientation.interfaces.Orientation3DReadOnly;
import us.ihmc.euclid.transform.RigidBodyTransform;
import us.ihmc.euclid.tuple3D.interfaces.Tuple3DReadOnly;
import us.ihmc.graphicsDescription.structure.Graphics3DNode;
import us.ihmc.javaFXToolkit.node.JavaFXGraphics3DNode;
import us.ihmc.mecano.multiBodySystem.interfaces.OneDoFJointBasics;
import us.ihmc.robotModels.FullHumanoidRobotModel;
import us.ihmc.robotModels.FullHumanoidRobotModelFactory;
import us.ihmc.robotModels.FullRobotModelUtils;
import us.ihmc.robotModels.description.RobotDefinitionConverter;
import us.ihmc.robotics.sensors.ForceSensorDefinition;
import us.ihmc.robotics.sensors.IMUDefinition;
import us.ihmc.scs2.definition.robot.RobotDefinition;
import us.ihmc.simulationConstructionSetTools.grahics.GraphicsIDRobot;
import us.ihmc.simulationconstructionset.graphics.GraphicsRobot;

public class JavaFXRobotVisualizer
{
   private GraphicsRobot graphicsRobot;
   private JavaFXGraphics3DNode robotRootNode;
   private final FullHumanoidRobotModel fullRobotModel;
   private final OneDoFJointBasics[] allJoints;
   private final int jointNameHash;
   private final boolean checkJointNameHash;
   private final int numberOfJoints;
   private final AtomicReference newConfigurationReference = new AtomicReference<>(null);

   private Runnable robotLoadedCallback;
   private boolean isRobotLoaded = false;
   private final Group rootNode = new Group();
   private boolean isRobotConfigurationInitialized = false;

   private final AnimationTimer animationTimer;

   public JavaFXRobotVisualizer(FullHumanoidRobotModelFactory fullRobotModelFactory)
   {
      this(fullRobotModelFactory, true);
   }

   public JavaFXRobotVisualizer(FullHumanoidRobotModelFactory fullRobotModelFactory, boolean checkJointNameHash)
   {
      fullRobotModel = fullRobotModelFactory.createFullRobotModel(false);

      allJoints = FullRobotModelUtils.getAllJointsExcludingHands(fullRobotModel);

      jointNameHash = calculateJointNameHash(allJoints, fullRobotModel.getForceSensorDefinitions(), fullRobotModel.getIMUDefinitions());
      this.checkJointNameHash = checkJointNameHash;
      this.numberOfJoints = allJoints.length;

      new Thread(() -> loadRobotModelAndGraphics(fullRobotModelFactory), "RobotVisualizerLoading").start();

      animationTimer = new AnimationTimer()
      {
         @Override
         public void handle(long now)
         {
            if (!isRobotLoaded)
               return;
            else if (rootNode.getChildren().isEmpty())
               rootNode.getChildren().add(robotRootNode);

            Configuration newConfiguration = newConfigurationReference.getAndSet(null);

            if (newConfiguration != null)
            {
               isRobotConfigurationInitialized = true;

               fullRobotModel.getRootJoint().setJointConfiguration(newConfiguration.rootJointPose);

               for (int i = 0; i < allJoints.length; i++)
                  allJoints[i].setQ(newConfiguration.jointAngles[i]);
            }

            fullRobotModel.getElevator().updateFramesRecursively();
            graphicsRobot.update();
            robotRootNode.update();

            if (robotLoadedCallback != null)
               robotLoadedCallback.run();
         }
      };
   }

   public static int calculateJointNameHash(OneDoFJointBasics[] joints, ForceSensorDefinition[] forceSensorDefinitions, IMUDefinition[] imuDefinitions)
   {
      CRC32 crc = new CRC32();
      for (OneDoFJointBasics joint : joints)
      {
         crc.update(joint.getName().getBytes());
      }

      for (ForceSensorDefinition forceSensorDefinition : forceSensorDefinitions)
      {
         crc.update(forceSensorDefinition.getSensorName().getBytes());
      }

      for (IMUDefinition imuDefinition : imuDefinitions)
      {
         crc.update(imuDefinition.getName().getBytes());
      }

      return (int) crc.getValue();
   }

   private void loadRobotModelAndGraphics(FullHumanoidRobotModelFactory fullRobotModelFactory)
   {
      RobotDefinition robotDefinition = fullRobotModelFactory.getRobotDefinition();
      graphicsRobot = new GraphicsIDRobot(robotDefinition.getName(),
                                          fullRobotModel.getElevator(),
                                          RobotDefinitionConverter.toGraphicsObjectsHolder(robotDefinition));
      robotRootNode = new JavaFXGraphics3DNode(graphicsRobot.getRootNode());
      robotRootNode.setMouseTransparent(true);
      addNodesRecursively(graphicsRobot.getRootNode(), robotRootNode);
      robotRootNode.update();

      isRobotLoaded = true;
   }

   public void start()
   {
      animationTimer.start();
   }

   public void stop()
   {
      animationTimer.stop();
   }

   private void addNodesRecursively(Graphics3DNode graphics3dNode, JavaFXGraphics3DNode parentNode)
   {
      JavaFXGraphics3DNode node = new JavaFXGraphics3DNode(graphics3dNode);
      parentNode.addChild(node);
      graphics3dNode.getChildrenNodes().forEach(child -> addNodesRecursively(child, node));
   }

   public void submitNewConfiguration(RobotConfigurationData robotConfigurationData)
   {
      if (checkJointNameHash && robotConfigurationData.getJointNameHash() != jointNameHash)
         throw new RuntimeException("Joint names do not match for RobotConfigurationData");
      else if (numberOfJoints != robotConfigurationData.getJointAngles().size())
         throw new RuntimeException("Inconsistent number of joints");

      newConfigurationReference.set(new Configuration(robotConfigurationData));
   }

   public void submitNewConfiguration(RigidBodyTransform rootJointTransform, ToDoubleFunction jointAngles)
   {
      newConfigurationReference.set(new Configuration(allJoints, rootJointTransform, jointAngles));
   }

   public void submitNewConfiguration(Tuple3DReadOnly rootJointTranslation, Orientation3DReadOnly rootJointOrientation, float[] jointAngles)
   {
      newConfigurationReference.set(new Configuration(rootJointTranslation, rootJointOrientation, jointAngles));
   }

   public void setRobotLoadedCallback(Runnable robotLoadedCallback)
   {
      this.robotLoadedCallback = robotLoadedCallback;
   }

   public FullHumanoidRobotModel getFullRobotModel()
   {
      return fullRobotModel;
   }

   public Node getRootNode()
   {
      return rootNode;
   }

   public boolean isRobotConfigurationInitialized()
   {
      return isRobotConfigurationInitialized;
   }

   private static class Configuration
   {
      private final RigidBodyTransform rootJointPose;
      private final float[] jointAngles;

      public Configuration(RobotConfigurationData robotConfigurationData)
      {
         rootJointPose = new RigidBodyTransform(robotConfigurationData.getRootOrientation(), robotConfigurationData.getRootPosition());
         jointAngles = robotConfigurationData.getJointAngles().toArray();
      }

      public Configuration(OneDoFJointBasics[] allJoints, RigidBodyTransform rootJointTransform, ToDoubleFunction jointNameToAngleFunction)
      {
         rootJointPose = rootJointTransform;
         jointAngles = new float[allJoints.length];
         for (int i = 0; i < allJoints.length; i++)
         {
            jointAngles[i] = (float) jointNameToAngleFunction.applyAsDouble(allJoints[i].getName());
         }
      }

      public Configuration(Tuple3DReadOnly rootJointTranslation, Orientation3DReadOnly rootJointOrientation, float[] jointAngles)
      {
         rootJointPose = new RigidBodyTransform(rootJointOrientation, rootJointTranslation);
         this.jointAngles = jointAngles;
      }
   }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy