1. This forum is obsolete and read-only. Feel free to contact us at support.keenswh.com

Is it possible to calculate the mass of a ship?

Discussion in 'Programming (In-game)' started by Semaphorism, Nov 25, 2015.

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

    Semaphorism Apprentice Engineer

    Messages:
    186
    I am trying to make cargo containers that will be shipped all across my server, however I have a limit on how much one can hold, simply because the ship design can't carry that much mass. So is it possible for a programmable block to calculate mass or all the cargo + blocks on it, since these are containers, I want to put a timer, programmable block and an LCD screen to show mass, and change it to red if its overweight.

    Much appreciated for any help!
     
  2. Pennywise

    Pennywise Apprentice Engineer

    Messages:
    338
    You can calculate total mass of all functional blocks and all inventory in a cycle. But armor blocks are unaccessible from scripts, so their mass stays unknown.
    Tho, you can still use F=ma to calculate empty ship mass (or simply set it as a constant in the script begining), memorize it, and than check container inventory mass.

    I've used this func to check inventory of a mining ship:

    Code:
     double CheckInventory(string Group, out int FeAmmount, out int CbAmmount, out int NiAmmount, out int MgAmmount, out int AuAmmount, out int AgAmmount, out int PtAmmount, out int SiAmmount, out int UAmmount, out int StoneAmmount, out int IceAmmount, out double CurrentMass)	 
    {	 
    List<IMyTerminalBlock> blocks=GetBlocksFromGroup(Group);	 
    FeAmmount=0;
    CbAmmount=0;
    NiAmmount=0;
    MgAmmount=0;
    AuAmmount=0;
    AgAmmount=0;
    PtAmmount=0;
    SiAmmount=0;
    UAmmount=0;
    StoneAmmount=0;
    IceAmmount=0;
    CurrentMass=0;
    //CargoMult=0;
    if (blocks.Count > 0)	  
    {	  
    double currentCargo=0;	 
    double maxCargo=0;  
     
    for (int x = 0; x < blocks.Count; x++)	  
    {	  
    var crate = blocks[x];	  
    var inventory = (IMyInventoryOwner)crate;		
    VRage.MyFixedPoint current = inventory.GetInventory(0).CurrentVolume;	  
    currentCargo += (float)current;	  
    VRage.MyFixedPoint max = inventory.GetInventory(0).MaxVolume;	  
    maxCargo += (float)max;
    //CargoMult=(float)max/8000;
    CurrentMass += (float)inventory.GetInventory(0).CurrentMass;
    var crateItems = inventory.GetInventory(0).GetItems();
     
    for (int j = crateItems.Count -1; j >= 0; j--)
    {
    if (crateItems[j].Content.SubtypeName == "Iron")
    {FeAmmount+=(int)crateItems[j].Amount;}
    else if (crateItems[j].Content.SubtypeName == "Cobalt")
    {CbAmmount+=(int)crateItems[j].Amount;} 
    else if (crateItems[j].Content.SubtypeName == "Nickel")
    {NiAmmount+=(int)crateItems[j].Amount;}
    else if (crateItems[j].Content.SubtypeName == "Magnesium")
    {MgAmmount+=(int)crateItems[j].Amount;}
    else if (crateItems[j].Content.SubtypeName == "Gold")
    {AuAmmount+=(int)crateItems[j].Amount;}
    else if (crateItems[j].Content.SubtypeName == "Silver")
    {AgAmmount+=(int)crateItems[j].Amount;}
    else if (crateItems[j].Content.SubtypeName == "Platinum")
    {PtAmmount+=(int)crateItems[j].Amount;}
    else if (crateItems[j].Content.SubtypeName == "Silicon")
    {SiAmmount+=(int)crateItems[j].Amount;}
    else if (crateItems[j].Content.SubtypeName == "Uranium")
    {UAmmount+=(int)crateItems[j].Amount;}
    else if (crateItems[j].Content.SubtypeName == "Stone")
    {StoneAmmount+=(int)crateItems[j].Amount;}
    else if (crateItems[j].Content.SubtypeName == "Ice")
    {IceAmmount+=(int)crateItems[j].Amount;}
    }
    }	  
    return 100*currentCargo/maxCargo;	 
    }	 
    else{return 0;}	 
    } 
     
    • Like Like x 1
  3. Sinbad

    Sinbad Senior Engineer

    Messages:
    2,788
    Sounds like yeu are setting up a standardized cargo system.
    Maybe a set of standard containers with a known tare mass? Then you just need to calculate cargo mass.
     
  4. Semaphorism

    Semaphorism Apprentice Engineer

    Messages:
    186
    I appreciate the help, but I think that script is missing functions, I need the total mass of the ship, including cargo, and all hull, etc.
     
  5. Pennywise

    Pennywise Apprentice Engineer

    Messages:
    338
    There is no way to get hull mass. You only can set empty ship mass, and than add cargo mass to get total.
     
    • Agree Agree x 1
  6. Semaphorism

    Semaphorism Apprentice Engineer

    Messages:
    186
    That is what I was wondering if I could get the hull mass with a programmable block.
     
  7. Pennywise

    Pennywise Apprentice Engineer

    Messages:
    338
    There is no direct access to ship mass value, but u can still use a weird method of getting it:

    1. log your Vector3D XYZ position, while ship is immobile
    2. set a certain ammount of thrust.
    3. log your Vector3D XYZ2 in 5 sec.
    4. Calculate Path length. S= (XYZ2 - XYZ).Length()
    5. Calculate acceleration. a= 2*S/t^2
    6. Calculate ship mass. m = Thrust/a

    Than memorize m, and calculate total ship mass by adding cargo mass to m.
     
    • Like Like x 1
    • Agree Agree x 1
  8. Sinbad

    Sinbad Senior Engineer

    Messages:
    2,788
    I wonder If I could make a mechanical cantilevered balance scale for weighing ships...
     
    • Funny Funny x 1
  9. Dr. Fuzenstein

    Dr. Fuzenstein Trainee Engineer

    Messages:
    31
    Actually, there IS a way to calculate the total mass of your ship! If you go to the info tab in the control panel of your ship, you will find a field labeled "Grid mass". Remember that because you will need to input it into the code.
    Code:
    void Main()  
    {  
     
    ////////////////Insert ship grid mass found in the info tab here/////////// ex: Grid mass: 26051
    double shipMass = 26051.0f;	 
    double totalMass = 0;   
       
    ////////////Get Cargo Containers////////////	
    	List<IMyTerminalBlock> cargo = new List<IMyTerminalBlock>();	
    	GridTerminalSystem.GetBlocksOfType<IMyCargoContainer>(cargo);	
    ////////////Get Refineries////////////	
    	List<IMyTerminalBlock> refineries = new List<IMyTerminalBlock>();	
    	GridTerminalSystem.GetBlocksOfType<IMyRefinery>(refineries);	
    ////////////Get Assemblers////////////	
    	List<IMyTerminalBlock> assemblers = new List<IMyTerminalBlock>();	 
    	GridTerminalSystem.GetBlocksOfType<IMyAssembler>(assemblers);	
    ////////////Get Connectors////////////	
    	List<IMyTerminalBlock> connectors = new List<IMyTerminalBlock>();	  
    	GridTerminalSystem.GetBlocksOfType<IMyShipConnector>(connectors);	
    ////////////Get Reactors////////////	
    	List<IMyTerminalBlock> reactors = new List<IMyTerminalBlock>();	   
    	GridTerminalSystem.GetBlocksOfType<IMyReactor>(reactors);	
     ////////////Get Oxygen Tanks  
    	List<IMyTerminalBlock> oxyTank = new List<IMyTerminalBlock>();	   
    	GridTerminalSystem.GetBlocksOfType<IMyOxygenTank>(oxyTank);	
     ////////////Get Oxygen Generators  
    	List<IMyTerminalBlock> oxyGen = new List<IMyTerminalBlock>();		
    	GridTerminalSystem.GetBlocksOfType<IMyOxygenGenerator>(oxyGen);	
      
    	
    	List<IMyInventoryItem> allItems = new List<IMyInventoryItem>();	
    	
    	
    ////////////Add Cargo Container Inventories to allItems////////////	
    	for(int i = 0; i < cargo.Count; i++)	
    	{	
    		var owner = (IMyInventoryOwner)cargo[i];	
    		var inventory = (IMyInventory)owner.GetInventory(0);	
    		var items = inventory.GetItems();	
    	
    		allItems.AddRange(items);	 
    	}	
    ////////////Add Refinery Inventories to allItems////////////Refineries have two inventories (input and output)	
    	for(int i = 0; i < refineries.Count; i++)	 
    	{	 
    		var owner = (IMyInventoryOwner)refineries[i];	 
    		var inventory = (IMyInventory)owner.GetInventory(0);	 
    		var items = inventory.GetItems();	 
    	 
    		allItems.AddRange(items);	 
    	
    		inventory = (IMyInventory)owner.GetInventory(1);	  
    		items = inventory.GetItems();	  
    	  
    		allItems.AddRange(items);	 
    	}	
    	 
    ////////////Add Assembler Inventories to allItems////////////Assemblers have two inventories (input and output)	
    	for(int i = 0; i < assemblers.Count; i++)	 
    	{	 
    		var owner = (IMyInventoryOwner)assemblers[i];	 
    		var inventory = (IMyInventory)owner.GetInventory(0);	 
    		var items = inventory.GetItems();	 
    	 
    		allItems.AddRange(items);	 
    	
    		inventory = (IMyInventory)owner.GetInventory(1);	  
    		items = inventory.GetItems();	  
    	  
    		allItems.AddRange(items);	 
    	}	
    	
    ////////////Add Connector Inventories to allItems////////////	
    	for(int i = 0; i < connectors.Count; i++)	 
    	{	 
    		var owner = (IMyInventoryOwner)connectors[i];	 
    		var inventory = (IMyInventory)owner.GetInventory(0);	 
    		var items = inventory.GetItems();	 
    	 
    		allItems.AddRange(items);	 
    	}	
    ////////////Add Reactor Inventories to allItems////////////	 
    	for(int i = 0; i < reactors.Count; i++)	  
    	{	  
    		var owner = (IMyInventoryOwner)reactors[i];	  
    		var inventory = (IMyInventory)owner.GetInventory(0);	  
    		var items = inventory.GetItems();	  
    	  
    		allItems.AddRange(items);	  
    	}   
    ////////////Add Oxygen Generator Inventories to allItems////////////	  
    	for(int i = 0; i < oxyGen.Count; i++)	   
    	{	   
    		var owner = (IMyInventoryOwner)oxyGen[i];	   
    		var inventory = (IMyInventory)owner.GetInventory(0);	   
    		var items = inventory.GetItems();	   
    	   
    		allItems.AddRange(items);	   
    	}   
    ////////////Add Oxygen Tank Inventories to allItems////////////	  
    	for(int i = 0; i < oxyTank.Count; i++)	   
    	{	   
    		var owner = (IMyInventoryOwner)oxyTank[i];	   
    		var inventory = (IMyInventory)owner.GetInventory(0);	   
    		var items = inventory.GetItems();	   
    	   
    		allItems.AddRange(items);	   
    	}   
       
    for(int i = 0; i < allItems.Count; i++)   
    {   
    	if(allItems[i].Content.ToString().Contains("Ore") == true || allItems[i].Content.ToString().Contains("Ingot") == true)   
    	{   
    		totalMass += (double)allItems[i].Amount;   
    	}   
       
    	if(allItems[i].Content.SubtypeName == "Girder") totalMass += (double)allItems[i].Amount*6;	
    	if(allItems[i].Content.SubtypeName == "SmallTube") totalMass += (double)allItems[i].Amount*4;	
    	if(allItems[i].Content.SubtypeName == "SteelPlate") totalMass += (double)allItems[i].Amount*20;	
    	if(allItems[i].Content.SubtypeName == "InteriorPlate") totalMass += (double)allItems[i].Amount*3;	
    	if(allItems[i].Content.SubtypeName == "MetalGrid") totalMass += (double)allItems[i].Amount*6;	
    	if(allItems[i].Content.SubtypeName == "Thrust") totalMass += (double)allItems[i].Amount*40;	
    	if(allItems[i].Content.SubtypeName == "Computer") totalMass += (double)allItems[i].Amount*0.2;	
    	if(allItems[i].Content.SubtypeName == "Reactor") totalMass += (double)allItems[i].Amount*25;	
    	if(allItems[i].Content.SubtypeName == "Motor") totalMass += (double)allItems[i].Amount*24;	
    	if(allItems[i].Content.SubtypeName == "LargeTube") totalMass += (double)allItems[i].Amount*25;	
    	if(allItems[i].Content.SubtypeName == "GravityGenerator") totalMass += (double)allItems[i].Amount*800;	
    	if(allItems[i].Content.SubtypeName == "BulletproofGlass") totalMass += (double)allItems[i].Amount*15;	
    	if(allItems[i].Content.SubtypeName == "Display") totalMass += (double)allItems[i].Amount*8;	
    	if(allItems[i].Content.SubtypeName == "Medical") totalMass += (double)allItems[i].Amount*150;	
    	if(allItems[i].Content.SubtypeName == "Construction") totalMass += (double)allItems[i].Amount*8;	
    	if(allItems[i].Content.SubtypeName == "Detector") totalMass += (double)allItems[i].Amount*5;	
    	if(allItems[i].Content.SubtypeName == "Explosives") totalMass += (double)allItems[i].Amount*2;	
    	if(allItems[i].Content.SubtypeName == "RadioCommunication") totalMass += (double)allItems[i].Amount*8;	
    	if(allItems[i].Content.SubtypeName == "SolarCell") totalMass += (double)allItems[i].Amount*8;	
    	if(allItems[i].Content.SubtypeName == "PowerCell") totalMass += (double)allItems[i].Amount*25;	
    	if(allItems[i].Content.SubtypeName == "Superconductor") totalMass += (double)allItems[i].Amount*15;	
    	if(allItems[i].Content.SubtypeName == "HandDrillItem") totalMass += (double)allItems[i].Amount*22;	
    	if(allItems[i].Content.SubtypeName == "WelderItem") totalMass += (double)allItems[i].Amount*5;	
    	if(allItems[i].Content.SubtypeName == "AutomaticRifleItem") totalMass += (double)allItems[i].Amount*3;	
    	if(allItems[i].Content.SubtypeName == "AngleGrinderItem") totalMass += (double)allItems[i].Amount*3;	
    	if(allItems[i].Content.SubtypeName == "NATO_5p56x45mm") totalMass += (double)allItems[i].Amount*0.45;	
    	if(allItems[i].Content.SubtypeName == "NATO_25x184mm") totalMass += (double)allItems[i].Amount*35;	 
    	if(allItems[i].Content.SubtypeName == "Missile200mm") totalMass += (double)allItems[i].Amount*45;	
    	if(allItems[i].Content.SubtypeName == "HydrogenBottle") totalMass += (double)allItems[i].Amount*30;	
    	if(allItems[i].Content.SubtypeName == "OxygenBottle") totalMass += (double)allItems[i].Amount*30;	
       
       
    }   
       
    totalMass += shipMass;   
      
    }
    All done!
     
  10. DoubleCouponDay

    DoubleCouponDay Apprentice Engineer

    Messages:
    123
    I believe IMyCubeBlock has a mass property but i never used it. This is for accessible blocks only, like pennywise said. A much cleaner way is to get the user to input the total mass as argument since its already there on the HUD.
     
  11. Dr. Fuzenstein

    Dr. Fuzenstein Trainee Engineer

    Messages:
    31
    Yes but unfortunately the IMyCubeBlock.Mass only returns the mass value of the block itself and not the contents.
     
  12. albmar

    albmar Trainee Engineer

    Messages:
    69
    @Dr. Fuzenstein: All blocks that have an inventory are implementing IMyInventoryOwner. Instead of getting all different block types that have an inventory you could simply get all blocks of type IMyInventoryOwner. In addition you don't have to calculate the mass of the inventory for each item by yourself. IMyInventory has a property CurrentMass, which gives you the total amount of mass in kg of the items being in the given inventory.
    Also note that the "Grid mass" displayed at the terminal already contains the mass of the items. So the grid mass is already the total mass. You can subtract the total inventory mass and the mass of each terminal block to get the mass of the blocks that you can't get otherwise. One disadvantage of this method is, that you cannot automatically measure the mass. You always have to add the grid mass manually if some non-terminal block has been altered, removed or added.
     
    • Like Like x 1
  13. Ronin1973

    Ronin1973 Master Engineer

    Messages:
    4,964
    The easiest way to solve the problem is as Pennywise stated, enter the dry weight (no cargo) manually. This should be a constant unless the ship is damaged or you add blocks. From there you just need to calculate the weight of the cargo.

    But some of the challenge is as you increase altitude your atmos. thrusters decrease in performance. Once they stop supplying lift, the ship will fall. Now you'll need enough thrust to counteract the mass at a constant speed of 104 m/s PLUS the(mass* 9.85m/s). All of this happens as the ship is falling and engine performance is increasing.

    I don't think you can script your way out of competent piloting, experience, and decision-making. I'd either redesign the ship to carry a payload much lower than its maximum upward acceleration, or not share the ship with anyone who isn't a rated pilot.

    I always test my atmospheric ships with full cargo bays to figure out performance and then post the recommended weight limits on an LCD. There are too many variables to rely on a script.
     
  14. DoubleCouponDay

    DoubleCouponDay Apprentice Engineer

    Messages:
    123
    @Ronin1973 I think there is a niche for this idea, or at least calculate with cargo full mass during design. we can get all thrusters containing "forward" and add a set amount of force F= MA for every thruster. Op wants to know if it can still get off the ground so you could print to panel during design or while mining.
     
  15. Ronin1973

    Ronin1973 Master Engineer

    Messages:
    4,964
    Yes, however if you copy n paste the ship (blueprint it), load it up with cargo in creative, then fly it on survival in a test world, you can gauge first hand. There's still a niche for test pilots. :)

    For small ships, the rule of thumb is one large thruster per medium cargo bay. That should cover a conservatively designed ship.

    Here's where you'll go wrong: you have enough force to lift the ship off the ground and gently ease into a hover. But as soon as you reach enough downward velocity, you enter a terminal dive that you can't get out of: either you run out of sky or you simply aren't producing enough Newton's of force to reduce your velocity and you are pegged at the max speed of 104 m/s.

    Then envelope swings wildly depending on the variables of vectored thruster power (depending on altitude), the maneuver (always a wild-card), the mass of the ship (variable due to cargo load), your altitude (run out of sky and everything else just doesn't matter). It's possible to do the calculations, certainly. However, being able to use them practically is completely another.

    Load your ship to capacity. Get it up to around 5000 meters. Turn off your dampeners and let it fall to earth until you reach 104m/s. Turn back on the dampeners. If you manage to stop just before you hit the ground, that's your heaviest POSSIBLE load. Yet you still have to consider more in-game "real world" usage where you're less than 1,000 meters off of the deck. Oh, and what happens it the terrain isn't level? Hey that's another variable. :)

    You can't control for all of the variables. Just come up with a maximum recommended mass for the ship and post it. The rest is just good piloting, depending on the conditions and the daring of the pilot.
     
  16. Dr. Fuzenstein

    Dr. Fuzenstein Trainee Engineer

    Messages:
    31
    I wasn't able to find a way to get the inventory mass so thanks for that! Also the "Grid mass" in the info tab only contains the mass of the ship's actual blocks and does NOT contain inventory mass meaning that the only time this value should be changed in the code is when you change blocks on the grid.
     
  17. Arcturus

    Arcturus Senior Engineer

    Messages:
    1,649
    Uh... I saw the info tab mass changing yesterday when I was loading a transport with cargo prior to ascent.
     
  18. Dr. Fuzenstein

    Dr. Fuzenstein Trainee Engineer

    Messages:
    31
    @Arcturus Silly me! It seems I was mistaken. Thanks for the correction.
     
  19. plaYer2k

    plaYer2k Master Engineer

    Messages:
    3,160
    Just a small reminder here.

    Thanks to that glorious idea that with higher inventory multiplier people shouldnt just be able to carry more in their containers but it also being easier, the actual inventory mass is divided by the inventory multiplier.

    So given a ship with an empty mass of 1 000 000 kg and a payload of 9 000 000 kg you get the following situation:
    1x inventory > 10 000 000 kg mass total
    3x inventory > 4 000 000 kg mass total
    10 inventory > 1 900 000 kg mass total

    If you ignore, you will get very weird readouts.
     
  20. midspace

    midspace Senior Engineer

    Messages:
    2,224
    IMyInventoryOwner has been marked obsolete. You need to stop using it.

    Code:
    private double GetCargoMass()
    {
    	double mass = 0;
    	List<IMyTerminalBlock> blocks = new List<IMyTerminalBlock>();
    	GridTerminalSystem.GetBlocks(blocks);
    	for (int i = 0; i < blocks.Count; i++)
    	{
    		var count = blocks[i].GetInventoryCount(); // Multiple inventories in Refineriers, Assemblers, Arc Furnances.
    		for (var inv = 0; inv < count; inv++)
    		{
    			var inventory = blocks[i].GetInventory(inv);
    			if (inventory != null) // null means, no items in inventory.
    				mass += (double)inventory.CurrentMass;
    		}
    	}
    	return mass;
    }
     
    • Like Like x 1
  21. Innoble

    Innoble Apprentice Engineer

    Messages:
    238
    You can, in fact, script your way out of competent piloting. The main way of doing this is to fly up to an altitude of 4000-5000 m and then to where you want to go (to avoid any mountains). Take it to a spot straight above your destination landing zone and then lower it at a slow speed. If, say, you travel between two stations of which you know the GPS coördinates, you will also know the altitude of the target and you can safely drop out of the sky (because your script knows when to hit the brakes).

    This is even possible with all thrusters pointing in the same direction and without any use of inertial dampeners. You can take into account the following factors:

    -Altitude, by way of knowing the planet center.

    -Effect of altitude on atmospheric thrusters. Add a factor of 10000/(10000 - Flight altitude) to the required thrust to stay level (which is mass * gravitational acceleration).

    -As stated before: base mass from the ship terminal (not through script) with added inventory mass (from script) to figure into the calculations.

    -Lack of power, in case you are too low on battery or reactor power (you multiply atmospheric thruster power by the fraction of power you can manage). Sometimes you have a design that can almost power a large thruster, but is a bit short.

    -Velocity in both the vertical and horizontal direction (using data storage of position to calculate velocity and then using dotproducts with the gravity vector)

    -Required acceleration in both a horizontal and a vertical direction. I use principle critical dampening for this in the video in this thread to accelerate and decelerate at exactly the right rates to stop in midair (vertically when arriving at the correct altitude, or horizontally, when arriving at the destination).

    -You rotate the ship in such a way that you have both enough horizontal and vertical thrust (possibly lowering the atmospheric thruster power to make sure you get the sweet spot for both thrust components). The math is not easy, but only one guy has to come up with it right? Once it's right, it's right. With human piloting, every flight will be different and there's always gonna be the one time where the ground seems to approach faster than you intended.

    I have been toying with the idea of making a tiny 1 person transport that takes GPS coördinates as input and safely lands you there, no matter where it is on the planet. Then there is no need for any piloting skills. If you watch the video I mentioned, you will see my "beans" do almost exactly this (they come to a full stop at a set altitude above a target location, this means they can do the same at a lower altitude e.g. a landing zone).
     
  22. Bleuhazenfurfle

    Bleuhazenfurfle Apprentice Engineer

    Messages:
    284
    Reading through this discussion, only makes me even more certain basic ship mass information (any two of: with cargo, without cargo, an cargo alone) should be right there in the PB's GTS. Fancy stuff like centre of mass should be stored in the GTS to if it's actually calculated at, all like by the physics system, if not, then it leaves the scripters something to do. But for basic stuff like this, if the game has it, then why not make it available to the scripts?

    I really don't understand the rationale behind forcing scripters, especially in-game scripters with all it's safety hand-holding interfaces and what-not, to re-calculate lower level quantities and reproduce lower level systems that already exist in the game in a vastly more efficient implementation, while simultaneously having to count script execution time and worry about script memory use. If we know the mass of our ship, we don't have to burn precious time calculating the damn thing over and over. Leave scripts to do the higher level stuff that isn't suitable for incorporation into the core system.

    I sometimes wonder how many scripters have a library of code they just copy and paste directly into every script they write, to give them a bunch of basic functionality the game already has and should be giving them for free.
     
    • Agree Agree x 1
Thread Status:
This last post in this thread was made more than 31 days old.