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

us.ihmc.scs2.session.remote.RemoteSession Maven / Gradle / Ivy

The newest version!
package us.ihmc.scs2.session.remote;

import us.ihmc.commons.Conversions;
import us.ihmc.graphicsDescription.conversion.YoGraphicConversionTools;
import us.ihmc.robotDataLogger.YoVariableClientInterface;
import us.ihmc.robotDataLogger.handshake.LogHandshake;
import us.ihmc.robotDataLogger.handshake.YoVariableHandshakeParser;
import us.ihmc.robotDataLogger.util.DebugRegistry;
import us.ihmc.robotDataLogger.websocket.command.DataServerCommand;
import us.ihmc.scs2.definition.robot.RobotDefinition;
import us.ihmc.scs2.definition.robot.RobotStateDefinition;
import us.ihmc.scs2.definition.terrain.TerrainObjectDefinition;
import us.ihmc.scs2.definition.yoGraphic.YoGraphicDefinition;
import us.ihmc.scs2.definition.yoGraphic.YoGraphicGroupDefinition;
import us.ihmc.scs2.session.Session;
import us.ihmc.scs2.session.SessionMode;
import us.ihmc.scs2.session.SessionProperties;
import us.ihmc.scs2.session.tools.RobotModelLoader;
import us.ihmc.scs2.simulation.robot.Robot;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;

public class RemoteSession extends Session
{
   private static final double MAX_DELAY_MILLI = 200.0;

   private YoVariableClientInterface yoVariableClientInterface;

   private final String sessionName;
   private final List robots = new ArrayList<>();
   private final List robotDefinitions = new ArrayList<>();
   private final List yoGraphicDefinitions = new ArrayList<>();
   private final Runnable robotStateUpdater;

   private final AtomicLong serverTimestamp = new AtomicLong(-1);
   private final AtomicLong latestDataTimestamp = new AtomicLong(-1);
   private final LoggerStatusUpdater loggerStatusUpdater = new LoggerStatusUpdater();

   private int bufferRecordTickPeriod = 1;
   private boolean initializeServerUpdateRate = true;

   public RemoteSession(YoVariableClientInterface yoVariableClientInterface,
                        LogHandshake handshake,
                        YoVariableHandshakeParser handshakeParser,
                        DebugRegistry debugRegistry)
   {
      super();

      this.yoVariableClientInterface = yoVariableClientInterface;

      sessionName = yoVariableClientInterface.getServerName();

      rootRegistry.addChild(handshakeParser.getRootRegistry());
      rootRegistry.addChild(debugRegistry.getYoRegistry());
      yoGraphicDefinitions.add(new YoGraphicGroupDefinition("SCS1 YoGraphics",
                                                            YoGraphicConversionTools.toYoGraphicDefinitions(handshakeParser.getSCS1YoGraphics())));
      yoGraphicDefinitions.addAll(handshakeParser.getSCS2YoGraphics());

      RobotDefinition robotDefinition = RobotModelLoader.loadModel(handshake.getModelName(),
                                                                   handshake.getModelLoaderClass(),
                                                                   handshake.getResourceDirectories(),
                                                                   handshake.getModel(),
                                                                   handshake.getResourceZip());
      if (robotDefinition != null)
      {
         robotDefinitions.add(robotDefinition);
         Robot robot = new Robot(robotDefinition, getInertialFrame());
         robots.add(robot);
         robotStateUpdater = RobotModelLoader.setupRobotUpdater(robot, handshakeParser, rootRegistry);
      }
      else
      {
         robotStateUpdater = null;
      }

      setSessionMode(SessionMode.RUNNING);
      setSessionDTSeconds(handshakeParser.getDt());
      setSessionModeTask(SessionMode.RUNNING, () ->
      {
         if (!this.yoVariableClientInterface.isConnected())
            setSessionMode(SessionMode.PAUSE);
         /* Do nothing, the client thread calls runTick(). */
      });
      addSessionPropertiesListener(properties ->
                                   {
                                      if (properties.getActiveMode() == SessionMode.RUNNING)
                                         reconnect();
                                      else
                                         disconnect();
                                   });
      setDesiredBufferPublishPeriod(Conversions.secondsToNanoseconds(1.0 / 60.0));
   }

   public long getDelay()
   {
      return serverTimestamp.get() - latestDataTimestamp.get();
   }

   @Override
   protected long computeRunTaskPeriod()
   {
      return Conversions.secondsToNanoseconds(0.01);
   }

   @Override
   protected long computePlaybackTaskPeriod()
   {
      /*
       * We let the yoVariableClient handle the bufferRecordTickPeriod feature, so we're not setting
       * updating the corresponding field in Session. Thus, it cannot compute the playback DT properly
       * without temporarily setting the Session.bufferRecordTickPeriod.
       */
      int superBufferRecordTickPeriod = super.getBufferRecordTickPeriod();
      super.setBufferRecordTickPeriod(bufferRecordTickPeriod);
      long playbackTaskPeriod = super.computePlaybackTaskPeriod();
      super.setBufferRecordTickPeriod(superBufferRecordTickPeriod);
      return playbackTaskPeriod;
   }

   @Override
   public SessionProperties getSessionProperties()
   {
      return new SessionProperties(getActiveMode(),
                                   getRunAtRealTimeRate(),
                                   getPlaybackRealTimeRate(),
                                   getSessionDTNanoseconds(),
                                   bufferRecordTickPeriod,
                                   getRunMaxDuration());
   }

   public void receivedTimestampOnly(long timestamp)
   {
      serverTimestamp.set(timestamp);
   }

   public void receivedTimestampAndData(long timestamp)
   {
      if (!hasSessionStarted() || getActiveMode() != SessionMode.RUNNING)
         return;

      if (initializeServerUpdateRate)
      {
         updateServerUpdateRate();
         initializeServerUpdateRate = false;
         return;
      }

      latestDataTimestamp.set(timestamp);
      runTick();
   }

   private void reconnect()
   {
      if (yoVariableClientInterface.isConnected())
         return;

      sharedBuffer.setInPoint(sharedBuffer.getProperties().getCurrentIndex());

      try
      {
         if (yoVariableClientInterface.reconnect())
            updateServerUpdateRate();
      }
      catch (IOException e)
      {
         e.printStackTrace();
      }
   }

   private void disconnect()
   {
      if (!yoVariableClientInterface.isConnected())
         return;

      initializeServerUpdateRate = true;
      yoVariableClientInterface.disconnect();
   }

   @Override
   protected double doSpecificRunTick()
   {
      if (robotStateUpdater != null)
         robotStateUpdater.run();
      return Conversions.nanosecondsToSeconds(latestDataTimestamp.get());
   }

   @Override
   protected void initializeRunTick()
   {
      if (firstRunTick)
      {
         sharedBuffer.incrementBufferIndex(true);
         sharedBuffer.setInPoint(sharedBuffer.getProperties().getCurrentIndex());
         sharedBuffer.processLinkedPushRequests(false);
         nextRunBufferRecordTickCounter = 0;
         firstRunTick = false;
      }
      else if (nextRunBufferRecordTickCounter <= 0)
      {
         sharedBuffer.incrementBufferIndex(true);
         sharedBuffer.processLinkedPushRequests(false);
      }
   }

   @Override
   protected void finalizeRunTick(boolean forceWriteBuffer)
   {
      if (forceWriteBuffer || Conversions.nanosecondsToMilliseconds(getDelay()) < MAX_DELAY_MILLI * bufferRecordTickPeriod)
      {
         super.finalizeRunTick(forceWriteBuffer);
      }
      else
      {
         sharedBuffer.writeBuffer();
         processBufferRequests(false);
         publishBufferProperties(sharedBuffer.getProperties());
      }
   }

   public void receivedCommand(DataServerCommand command, int argument)
   {
      loggerStatusUpdater.updateStatus(command, argument);
   }

   @Override
   public void setBufferRecordTickPeriod(int bufferRecordTickPeriod)
   {
      if (bufferRecordTickPeriod == this.bufferRecordTickPeriod)
         return;
      this.bufferRecordTickPeriod = Math.max(1, bufferRecordTickPeriod);
      updateServerUpdateRate();
   }

   private void updateServerUpdateRate()
   {
      int updateRateInMilliseconds = (int) TimeUnit.NANOSECONDS.toMillis(bufferRecordTickPeriod * getSessionDTNanoseconds());
      yoVariableClientInterface.setVariableUpdateRate(updateRateInMilliseconds);
   }

   public void close()
   {
      if (yoVariableClientInterface != null)
      {
         if (yoVariableClientInterface.isConnected())
            yoVariableClientInterface.disconnect();
         yoVariableClientInterface.stop();
      }
   }

   public void sendCommandToYoVariableServer(DataServerCommand command, int argument)
   {
      if (yoVariableClientInterface != null && yoVariableClientInterface.isConnected())
         yoVariableClientInterface.sendCommand(command, argument);
   }

   @Override
   public String getSessionName()
   {
      return sessionName;
   }

   @Override
   public List getRobotDefinitions()
   {
      return robotDefinitions;
   }

   @Override
   public List getTerrainObjectDefinitions()
   {
      return Collections.emptyList();
   }

   @Override
   public List getYoGraphicDefinitions()
   {
      return yoGraphicDefinitions;
   }

   @Override
   public List getCurrentRobotStateDefinitions(boolean initialState)
   {
      return robots.stream().map(Robot::getCurrentRobotStateDefinition).collect(Collectors.toList());
   }

   public LoggerStatusUpdater getLoggerStatusUpdater()
   {
      return loggerStatusUpdater;
   }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy