Welcome to Keen Software House Forums! Log in or Sign up to interact with the KSH community.
  1. You are currently browsing our forum as a guest. Create your own forum account to access all forum functionality.

Help with thrusters on rotors

Discussion in 'Programming (In-game)' started by haibusa2005, Jan 18, 2020.

Thread Status:
This last post in this thread was made more than 31 days old.
  1. haibusa2005 Trainee Engineer

    Messages:
    40
    Hello all!

    I'm trying to control a ship which has 4 wings - 2 on each side with 4 hydrogen thrusters on each wing. I want to set a command from cockpit so the thrusters face forward, downward or backward. During the transition from one position to the target position, the thrusters must be off. They should fire only when the current angle is withing tolerance of 1.5° from target position. When the position is within the tolerance, the rotation speed should become 0 and the rotors will be locked.

    I wrote some code which works, but I am having a problem when the wings reach target position - rotors start to switch directions violently, but rotation speed is 0 and the rotors are locked. If I leave the rotors without lock, everything works fine. If I switch the lock on, Klang comes to say "Hi". I also use Whip's Subgrid Thruster Manager v40

    Workshop link of the playground - https://steamcommunity.com/sharedfiles/filedetails/?id=1972433316
    Buttons 1, 2 and 3 from the toolbar set position.

    I am looking for some advice regarding the lock and my coding (programming is a hobby of mine). Thanks in advance!

    EDIT: Added some literacy. Also, I will get rid of the entire get current command thing at some point, I know it's moronic :)

    Code:
    readonly float RotorVelocity = 8f;
    
    public Program()
    {
    
      Runtime.UpdateFrequency = UpdateFrequency.Update10;
      PopulateThrusterGroups();
      PopulateRotors();
    }
    
    public void Main(string argument, UpdateType updateSource)
    {
      //a gravity generator is named as current command
      IMyMotorAdvancedStator RotorFR = GridTerminalSystem.GetBlockWithName("RotorFR") as IMyMotorAdvancedStator;
      Echo($"Current angle of RotorFR is {RotorFR.Angle * 180 / Math.PI}");
      Echo($"Current command is: {GetCurrentCommand()}");
      string CurrentCommand = GetCurrentCommand();
    
      switch (CurrentCommand)
      {
      case "FaceForward":
      foreach (IMyMotorAdvancedStator CurrentRotor in Rotors)
      {
      FaceRotorForward(CurrentRotor);
      if (IsAngleInLimits(CurrentRotor, CurrentCommand))
      {
      ControlThrusters(GetThrusterGroup(CurrentRotor), true);
      //CurrentRotor.RotorLock = true;
      CurrentRotor.TargetVelocityRPM = 0;
      }
      else
      {
      ControlThrusters(GetThrusterGroup(CurrentRotor), false);
      }
      }
      break;
    
      case "FaceDownward":
      foreach (IMyMotorAdvancedStator CurrentRotor in Rotors)
      {
      FaceRotorDown(CurrentRotor);
      if (IsAngleInLimits(CurrentRotor, CurrentCommand))
      {
      ControlThrusters(GetThrusterGroup(CurrentRotor), true);
      //CurrentRotor.RotorLock = true;
      CurrentRotor.TargetVelocityRPM = 0;
      }
      else
      {
      ControlThrusters(GetThrusterGroup(CurrentRotor), false);
      }
      }
      break;
    
      case "FaceBackward":
      foreach (IMyMotorAdvancedStator CurrentRotor in Rotors)
      {
      FaceRotorBackward(CurrentRotor);
      if (IsAngleInLimits(CurrentRotor, CurrentCommand))
      {
      ControlThrusters(GetThrusterGroup(CurrentRotor), true);
      //CurrentRotor.RotorLock = true;
      CurrentRotor.TargetVelocityRPM = 0;
      }
      else
      {
      ControlThrusters(GetThrusterGroup(CurrentRotor), false);
      }
      }
      break;
    
      default:
      Echo("Invalid command detected!");
      break;
      }
    }
    
    public void ControlThrusters(List<IMyThrust> ThrusterGroup, bool IsEnabled) //Powers on or off all thrusters in the list
    
    {
      foreach (IMyThrust CurrentThruster in ThrusterGroup)
      {
      CurrentThruster.Enabled = IsEnabled;
      }
    }
    
    public string GetCurrentCommand()//Gets all the gravity generators and returns the name of the first one
    {
      List<IMyGravityGenerator> GravityGenerators = new List<IMyGravityGenerator>();
      GridTerminalSystem.GetBlocksOfType<IMyGravityGenerator>(GravityGenerators);
      if (GravityGenerators[0] == null) { throw new Exception("No gravity generators found!"); }
      return GravityGenerators[0].CustomName;
    }
    
    public void FaceRotorForward(IMyMotorAdvancedStator CurrentRotor)
    {
      if(IsAngleInLimits(CurrentRotor, GetCurrentCommand())) { return; }
    
      float Velocity = RotorVelocity;
    
      if (CurrentRotor.CustomName == "RotorFR" | CurrentRotor.CustomName == "RotorRR")
      {
      Velocity = RotorVelocity * -1;
      }
    
      CurrentRotor.RotorLock = false;
      CurrentRotor.UpperLimitDeg = 90;
      CurrentRotor.LowerLimitDeg = 90;
      CurrentRotor.TargetVelocityRPM = Velocity;
    
    }
    
    public void FaceRotorDown(IMyMotorAdvancedStator CurrentRotor)
    {
      if (IsAngleInLimits(CurrentRotor, GetCurrentCommand())) { return; }
    
      float Velocity = RotorVelocity;
      float UpperLimit = 0;
      float LowerLimit = 0;
    
      if (CurrentRotor.CustomName == "RotorFR" | CurrentRotor.CustomName == "RotorRR")
      {
      Velocity = RotorVelocity * -1;
      UpperLimit = 180;
      LowerLimit = 180;
      }
    
    
      CurrentRotor.RotorLock = false;
      CurrentRotor.UpperLimitDeg = UpperLimit;
      CurrentRotor.LowerLimitDeg = LowerLimit;
    
      double RotorCurrentAngle = CurrentRotor.Angle * 180 / Math.PI;
      if (RotorCurrentAngle < 0) //Faces backward
      {
      CurrentRotor.TargetVelocityRPM = Velocity;
      }
    
      if (RotorCurrentAngle > 0) //Faces forward
      {
      CurrentRotor.TargetVelocityRPM = Velocity * -1;
      }
    }
    
    public void FaceRotorBackward(IMyMotorAdvancedStator CurrentRotor)
    {
      if (IsAngleInLimits(CurrentRotor, GetCurrentCommand())) { return; }
    
      float Velocity = RotorVelocity;
    
      if (CurrentRotor.CustomName == "RotorFR" | CurrentRotor.CustomName == "RotorRR")
      {
      Velocity = RotorVelocity * -1;
      }
      CurrentRotor.RotorLock = false;
      CurrentRotor.UpperLimitDeg = -90;
      CurrentRotor.LowerLimitDeg = -90;
      CurrentRotor.TargetVelocityRPM = Velocity * -1;
    }
    
    readonly string[] ThrusterNamesFrontLeft = { "Thruster 1 FL", "Thruster 2 FL", "Thruster 3 FL", "Thruster 4 FL" };
    readonly string[] ThrusterNamesFrontRight = { "Thruster 1 FR", "Thruster 2 FR", "Thruster 3 FR", "Thruster 4 FR" };
    readonly string[] ThrusterNamesRearLeft = { "Thruster 1 RL", "Thruster 2 RL", "Thruster 3 RL", "Thruster 4 RL" };
    readonly string[] ThrusterNamesRearRight = { "Thruster 1 RR", "Thruster 2 RR", "Thruster 3 RR", "Thruster 4 RR" };
    List<IMyThrust> ThrusterGroupFrontLeft = new List<IMyThrust>();
    List<IMyThrust> ThrusterGroupFrontRight = new List<IMyThrust>();
    List<IMyThrust> ThrusterGroupRearLeft = new List<IMyThrust>();
    List<IMyThrust> ThrusterGroupRearRight = new List<IMyThrust>();
    List<List<IMyThrust>> ThrusterGroups = new List<List<IMyThrust>>();
    
    public void PopulateThrusterGroups()//adds all the thrusters specified to the corresponding thruster list and then all the lists to the ThrusterGroups list
    {
    
      for (int i = 0; i < ThrusterNamesFrontLeft.GetUpperBound(0) + 1; i++)
      {
      ThrusterGroupFrontLeft.Add(GridTerminalSystem.GetBlockWithName(ThrusterNamesFrontLeft[i]) as IMyThrust);
      if (ThrusterGroupFrontLeft[i] == null) { throw new Exception($"Thruster with name {ThrusterNamesFrontLeft[i]} not found!"); }
      }
    
      for (int i = 0; i < ThrusterNamesFrontRight.GetUpperBound(0) + 1; i++)
      {
      ThrusterGroupFrontRight.Add(GridTerminalSystem.GetBlockWithName(ThrusterNamesFrontRight[i]) as IMyThrust);
      if (ThrusterGroupFrontRight[i] == null) { throw new Exception($"Thruster with name {ThrusterNamesFrontRight[i]} not found!"); }
      }
    
      for (int i = 0; i < ThrusterNamesRearLeft.GetUpperBound(0) + 1; i++)
      {
      ThrusterGroupRearLeft.Add(GridTerminalSystem.GetBlockWithName(ThrusterNamesRearLeft[i]) as IMyThrust);
      if (ThrusterGroupRearLeft[i] == null) { throw new Exception($"Thruster with name {ThrusterNamesRearLeft[i]} not found!"); }
      }
    
      for (int i = 0; i < ThrusterNamesRearRight.GetUpperBound(0) + 1; i++)
      {
      ThrusterGroupRearRight.Add(GridTerminalSystem.GetBlockWithName(ThrusterNamesRearRight[i]) as IMyThrust);
      if (ThrusterGroupRearRight[i] == null) { throw new Exception($"Thruster with name {ThrusterNamesRearRight[i]} not found!"); }
      }
    
      ThrusterGroups.Add(ThrusterGroupFrontLeft);
      ThrusterGroups.Add(ThrusterGroupFrontRight);
      ThrusterGroups.Add(ThrusterGroupRearLeft);
      ThrusterGroups.Add(ThrusterGroupRearRight);
    }
    
    readonly string[] RotorNames = { "RotorFL", "RotorRL", "RotorFR", "RotorRR" };
    
    
    List<IMyMotorAdvancedStator> Rotors = new List<IMyMotorAdvancedStator>();
    public void PopulateRotors() //adds all the rotors specified in RotorNames to the "Rotors" list
    {
      for (int i = 0; i < RotorNames.GetUpperBound(0) + 1; i++)
      {
      Rotors.Add(GridTerminalSystem.GetBlockWithName(RotorNames[i]) as IMyMotorAdvancedStator);
      if (Rotors[i] == null) { throw new Exception($"Rotor with name {RotorNames[i]} not found!"); }
      }
    
    }
    
    public void SetCurrentCommand(string Command) //sets the name of the gravity generator to the passed string
    {
      List<IMyGravityGenerator> GravityGenerators = new List<IMyGravityGenerator>();
      GridTerminalSystem.GetBlocksOfType<IMyGravityGenerator>(GravityGenerators);
      if (GravityGenerators.Count == 0) { throw new Exception("No gravity generators found!"); }
      GravityGenerators[0].CustomName = Command;
    }
    
    public List<IMyThrust> GetThrusterGroup(IMyMotorAdvancedStator CurrentRotor) //Returns a list of thrusters attached to the corresponding rotor
    {
    
      switch (CurrentRotor.CustomName)
      {
      case "RotorFL":
      {
      return ThrusterGroupFrontLeft;
      }
      case "RotorFR":
      {
      return ThrusterGroupFrontRight;
      }
      case "RotorRL":
      {
      return ThrusterGroupRearLeft;
      }
      case "RotorRR":
      {
      return ThrusterGroupRearRight;
      }
      }
      return null;
    }
    
    public bool IsAngleInLimits(IMyMotorAdvancedStator CurrentRotor, string CurrentCommand)//checks if rotor is in specified tolerance for the set command
    {
      float Tolerance = 1.5f;
      double CurrentRotorAngle = CurrentRotor.Angle * 180 / Math.PI;
    
      switch (CurrentCommand)
      {
      case "FaceForward":
      if (CurrentRotorAngle > 90 - Tolerance & CurrentRotorAngle < 90 + Tolerance) {return true;}
      return false;
    
      case "FaceDownward":
      float DownwardAngle = 0;
      if (CurrentRotor.CustomName == "RotorFR" | CurrentRotor.CustomName == "RotorRR") { DownwardAngle = 180; }
      if (CurrentRotorAngle > DownwardAngle - Tolerance & CurrentRotorAngle < DownwardAngle + Tolerance) { return true; }
      return false;
    
      case "FaceBackward":
      if (CurrentRotorAngle > -90 - Tolerance & CurrentRotorAngle < -90 + Tolerance) { return true; }
      return false;
      }
      return false;
    }
    
     
    Last edited: Jan 19, 2020
  2. Ronin1973 Master Engineer

    Messages:
    4,911
    I did a ship called the "Frog Foot" and solved some of the issues regarding the thruster logic. I use a flag in the custom name space for different groups of blocks and the seek out the first valid block in the List to make judgment calls. It's workshop under Ronin Planetary Industries. Feel free to study the code. It's under the Homebrew programmable block. I'm using Whiplash's code to handle the rotor and piston thrusters.
     
  3. haibusa2005 Trainee Engineer

    Messages:
    40
    I took a look at the code and believe that you solved the issue in the same manner as me. Maybe it has something to do with the way the rotor lock works. Thanks for your input! :)
     
Thread Status:
This last post in this thread was made more than 31 days old.