Mechanical grid now only requires torque to accelerate
This commit is contained in:
parent
e2a1b9601a
commit
65c3661f90
8 changed files with 83 additions and 54 deletions
|
@ -25,10 +25,16 @@ trait TNodeMechanical extends INode with IVectorWorld
|
||||||
def torque: Double
|
def torque: Double
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The mechanical load energy loss per second.
|
* The mechanical resistance of this node.
|
||||||
|
* Consider the moment of inertia, which equals mass * radius ^ 2
|
||||||
|
*
|
||||||
|
* Torque = Moment of Intertia * angular velocity
|
||||||
|
*
|
||||||
|
* A higher resistance or moment of inertia means that it is more difficult for this mechanical node to accelerate.
|
||||||
|
*
|
||||||
* @return Power loss in Watts.
|
* @return Power loss in Watts.
|
||||||
*/
|
*/
|
||||||
def getLoad = 10D
|
def inertia = 10D
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The radius of rotation
|
* The radius of rotation
|
||||||
|
@ -55,5 +61,5 @@ trait TNodeMechanical extends INode with IVectorWorld
|
||||||
*
|
*
|
||||||
* @param torque - force at an angle
|
* @param torque - force at an angle
|
||||||
*/
|
*/
|
||||||
def rotate(torque: Double, angularVelocity: Double)
|
def accelerate(torque: Double)
|
||||||
}
|
}
|
|
@ -32,6 +32,11 @@ object TileMotor
|
||||||
val fieldStrength = 1
|
val fieldStrength = 1
|
||||||
val coils = 10
|
val coils = 10
|
||||||
val area = 1
|
val area = 1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Motor constant is the product of: N (Number of coils), B (Magnetic Field Density), A (Area)
|
||||||
|
* Or, we can call it: N * Total Flux
|
||||||
|
*/
|
||||||
val motorConstant = fieldStrength * area * coils
|
val motorConstant = fieldStrength * area * coils
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +68,19 @@ class TileMotor extends SpatialTile(Material.iron) with TIO with TElectric with
|
||||||
override def start()
|
override def start()
|
||||||
{
|
{
|
||||||
super.start()
|
super.start()
|
||||||
updateConnectionMask()
|
updateConnections()
|
||||||
|
}
|
||||||
|
|
||||||
|
def updateConnections()
|
||||||
|
{
|
||||||
|
electricNode.connectionMask = ForgeDirection.VALID_DIRECTIONS.filter(getIO(_) > 0).map(d => 1 << d.ordinal()).foldLeft(0)(_ | _)
|
||||||
|
electricNode.positiveTerminals.clear()
|
||||||
|
electricNode.negativeTerminals.clear()
|
||||||
|
electricNode.positiveTerminals.addAll(getInputDirections())
|
||||||
|
electricNode.negativeTerminals.addAll(getOutputDirections())
|
||||||
|
electricNode.reconstruct()
|
||||||
|
notifyChange()
|
||||||
|
markUpdate()
|
||||||
}
|
}
|
||||||
|
|
||||||
override def update()
|
override def update()
|
||||||
|
@ -72,9 +89,10 @@ class TileMotor extends SpatialTile(Material.iron) with TIO with TElectric with
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Produce torque based on current.
|
* Produce torque based on current.
|
||||||
|
* T = NBA * I / (2pi)
|
||||||
*/
|
*/
|
||||||
val power = electricNode.power
|
val power = electricNode.power
|
||||||
val torque = TileMotor.motorConstant * electricNode.current
|
val torque = TileMotor.motorConstant * electricNode.current / (2 * Math.PI)
|
||||||
|
|
||||||
//TODO: Check if angular velocity should be generated based on torque
|
//TODO: Check if angular velocity should be generated based on torque
|
||||||
if (torque != 0)
|
if (torque != 0)
|
||||||
|
@ -83,7 +101,11 @@ class TileMotor extends SpatialTile(Material.iron) with TIO with TElectric with
|
||||||
/**
|
/**
|
||||||
* Motors produce emf or counter-emf by Lenz's law based on angular velocity
|
* Motors produce emf or counter-emf by Lenz's law based on angular velocity
|
||||||
* emf = change of flux/time
|
* emf = change of flux/time
|
||||||
* = (NBCos(x))/time
|
*
|
||||||
|
* After differentiation via chain rule:
|
||||||
|
* emf = NBAwSin(wt)
|
||||||
|
* emfMax = NBAw
|
||||||
|
* where w = angular velocity
|
||||||
*/
|
*/
|
||||||
val inducedEmf = TileMotor.motorConstant * mechNode.angularVelocity // * Math.sin(mechNode.angularVelocity * System.currentTimeMillis() / 1000d)
|
val inducedEmf = TileMotor.motorConstant * mechNode.angularVelocity // * Math.sin(mechNode.angularVelocity * System.currentTimeMillis() / 1000d)
|
||||||
electricNode.generateVoltage(inducedEmf * -1)
|
electricNode.generateVoltage(inducedEmf * -1)
|
||||||
|
@ -98,22 +120,10 @@ class TileMotor extends SpatialTile(Material.iron) with TIO with TElectric with
|
||||||
//Auto-set opposite side for unreachable sides
|
//Auto-set opposite side for unreachable sides
|
||||||
if (ioType != 0)
|
if (ioType != 0)
|
||||||
super.setIO(dir.getOpposite, (ioType % 2) + 1)
|
super.setIO(dir.getOpposite, (ioType % 2) + 1)
|
||||||
updateConnectionMask()
|
updateConnections()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def updateConnectionMask()
|
|
||||||
{
|
|
||||||
electricNode.connectionMask = ForgeDirection.VALID_DIRECTIONS.filter(getIO(_) > 0).map(d => 1 << d.ordinal()).foldLeft(0)(_ | _)
|
|
||||||
electricNode.positiveTerminals.clear()
|
|
||||||
electricNode.negativeTerminals.clear()
|
|
||||||
electricNode.positiveTerminals.addAll(getInputDirections())
|
|
||||||
electricNode.negativeTerminals.addAll(getOutputDirections())
|
|
||||||
electricNode.reconstruct()
|
|
||||||
notifyChange()
|
|
||||||
markUpdate()
|
|
||||||
}
|
|
||||||
|
|
||||||
@SideOnly(Side.CLIENT)
|
@SideOnly(Side.CLIENT)
|
||||||
override def renderDynamic(pos: Vector3, frame: Float, pass: Int): Unit =
|
override def renderDynamic(pos: Vector3, frame: Float, pass: Int): Unit =
|
||||||
{
|
{
|
||||||
|
|
|
@ -20,7 +20,7 @@ class NodeGear(parent: PartGear) extends NodeMechanical(parent: PartGear)
|
||||||
{
|
{
|
||||||
override def angleDisplacement = if (gear.getMultiBlock.isConstructed) Math.PI / 36 else Math.PI / 12
|
override def angleDisplacement = if (gear.getMultiBlock.isConstructed) Math.PI / 36 else Math.PI / 12
|
||||||
|
|
||||||
override def getLoad: Double =
|
override def inertia: Double =
|
||||||
{
|
{
|
||||||
return gear.tier match
|
return gear.tier match
|
||||||
{
|
{
|
||||||
|
|
|
@ -10,7 +10,7 @@ import resonant.lib.wrapper.ForgeDirectionWrapper._
|
||||||
|
|
||||||
class NodeGearShaft(parent: PartGearShaft) extends NodeMechanical(parent)
|
class NodeGearShaft(parent: PartGearShaft) extends NodeMechanical(parent)
|
||||||
{
|
{
|
||||||
override def getLoad: Double =
|
override def inertia: Double =
|
||||||
{
|
{
|
||||||
return shaft.tier match
|
return shaft.tier match
|
||||||
{
|
{
|
||||||
|
|
|
@ -11,11 +11,6 @@ import scala.collection.convert.wrapAll._
|
||||||
*/
|
*/
|
||||||
class GridMechanical extends GridNode[NodeMechanical] with IUpdate
|
class GridMechanical extends GridNode[NodeMechanical] with IUpdate
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* The energy loss of this grid
|
|
||||||
*/
|
|
||||||
private var load = 0D
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines if this grid is locked (invalid opposite gear connections)
|
* Determines if this grid is locked (invalid opposite gear connections)
|
||||||
*/
|
*/
|
||||||
|
@ -48,24 +43,26 @@ class GridMechanical extends GridNode[NodeMechanical] with IUpdate
|
||||||
{
|
{
|
||||||
nodes synchronized
|
nodes synchronized
|
||||||
{
|
{
|
||||||
load = 0
|
/**
|
||||||
|
* Consider this as the moment of inertia: how difficult it is to spin this object.
|
||||||
|
*/
|
||||||
nodes.foreach(
|
nodes.foreach(
|
||||||
n =>
|
n =>
|
||||||
{
|
{
|
||||||
n.torque = 0
|
n.torque = 0
|
||||||
n.angularVelocity = 0
|
// n.angularVelocity = 0
|
||||||
load += n.getLoad
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//TODO: Add deceleration
|
||||||
|
|
||||||
if (!isLocked)
|
if (!isLocked)
|
||||||
{
|
{
|
||||||
getNodes.filter(n => n.bufferTorque != 0 && n.bufferAngularVelocity != 0).foreach(
|
getNodes.filter(n => n.bufferTorque != 0).foreach(
|
||||||
n =>
|
n =>
|
||||||
{
|
{
|
||||||
allPassed = Seq(n)
|
allPassed = Seq(n)
|
||||||
recurse(Seq(n), deltaTime, n.bufferTorque, n.bufferAngularVelocity)
|
recurse(Seq(n), deltaTime, n.bufferTorque, 0)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -94,11 +91,22 @@ class GridMechanical extends GridNode[NodeMechanical] with IUpdate
|
||||||
}
|
}
|
||||||
|
|
||||||
n.bufferTorque = 0
|
n.bufferTorque = 0
|
||||||
n.bufferAngularVelocity = 0
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def calculateEquivalentInertia(passed: Seq[NodeMechanical]): Double =
|
||||||
|
{
|
||||||
|
val curr = passed.last
|
||||||
|
/**
|
||||||
|
* I1 + n^2 * I
|
||||||
|
* where n is the acceleration ratio
|
||||||
|
*/
|
||||||
|
var inertia = curr.inertia
|
||||||
|
inertia += curr.connections.map(c => c.radius(curr) / curr.radius(c) * calculateEquivalentInertia(passed :+ c)).foldLeft(0d)(_ + _)
|
||||||
|
return inertia
|
||||||
|
}
|
||||||
|
|
||||||
def recurse(passed: Seq[NodeMechanical], deltaTime: Double, torque: Double, angularVelocity: Double)
|
def recurse(passed: Seq[NodeMechanical], deltaTime: Double, torque: Double, angularVelocity: Double)
|
||||||
{
|
{
|
||||||
val curr = passed.last
|
val curr = passed.last
|
||||||
|
@ -138,19 +146,24 @@ class GridMechanical extends GridNode[NodeMechanical] with IUpdate
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//This is the first node.
|
/**
|
||||||
//Calculate energy loss
|
* This is the first node.
|
||||||
val power = torque * angularVelocity
|
* 1. Calculate equivalent moment of inertia of the mechanical system.
|
||||||
val netEnergy = Math.max(power - load * deltaTime, 0)
|
* 2. Determine the angular acceleration:
|
||||||
val netTorque = netEnergy * (torque / power)
|
* T = I * a
|
||||||
val netVelocity = netEnergy * (angularVelocity / power)
|
* a = T/I
|
||||||
|
* where I = inertia and a = angular acceleration
|
||||||
|
*/
|
||||||
|
val inertia = calculateEquivalentInertia(passed)
|
||||||
|
val netTorque = torque
|
||||||
|
val netAcceleration = torque / inertia
|
||||||
|
|
||||||
curr.torque += netTorque
|
curr.torque += netTorque
|
||||||
curr.angularVelocity += netVelocity * deltaTime
|
curr.angularVelocity += netAcceleration * deltaTime
|
||||||
curr.connections.foreach(c =>
|
curr.connections.foreach(c =>
|
||||||
{
|
{
|
||||||
allPassed :+= c
|
allPassed :+= c
|
||||||
recurse(passed :+ c, deltaTime, netTorque, netVelocity)
|
recurse(passed :+ c, deltaTime, netTorque, netAcceleration)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,6 @@ class NodeMechanical(parent: INodeProvider) extends NodeGrid[NodeMechanical](par
|
||||||
* Buffer values used by the grid to transfer mechanical energy.
|
* Buffer values used by the grid to transfer mechanical energy.
|
||||||
*/
|
*/
|
||||||
protected[grid] var bufferTorque = 0D
|
protected[grid] var bufferTorque = 0D
|
||||||
protected[grid] var bufferAngularVelocity = 0D
|
|
||||||
private var _torque = 0D
|
private var _torque = 0D
|
||||||
private var _angularVelocity = 0D
|
private var _angularVelocity = 0D
|
||||||
|
|
||||||
|
@ -80,22 +79,14 @@ class NodeMechanical(parent: INodeProvider) extends NodeGrid[NodeMechanical](par
|
||||||
*/
|
*/
|
||||||
def angleDisplacement = 0D
|
def angleDisplacement = 0D
|
||||||
|
|
||||||
override def rotate(torque: Double, angularVelocity: Double)
|
override def accelerate(torque: Double)
|
||||||
{
|
{
|
||||||
bufferTorque += torque
|
bufferTorque += torque
|
||||||
bufferAngularVelocity += angularVelocity
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def power: Double = torque * angularVelocity
|
def power: Double = torque * angularVelocity
|
||||||
|
|
||||||
/**
|
override def radius(other: TNodeMechanical) = 0.5
|
||||||
* Gets the torque of the mechanical device from a specific side
|
|
||||||
*
|
|
||||||
* @return force
|
|
||||||
*/
|
|
||||||
override def torque = _torque
|
|
||||||
|
|
||||||
def torque_=(newTorque: Double) = _torque = newTorque
|
|
||||||
|
|
||||||
def getMechanicalGrid: GridMechanical = super.grid.asInstanceOf[GridMechanical]
|
def getMechanicalGrid: GridMechanical = super.grid.asInstanceOf[GridMechanical]
|
||||||
|
|
||||||
|
@ -107,6 +98,15 @@ class NodeMechanical(parent: INodeProvider) extends NodeGrid[NodeMechanical](par
|
||||||
|
|
||||||
override def toString = "NodeMechanical [" + connections.size() + " Torque: " + BigDecimal(torque).setScale(2, BigDecimal.RoundingMode.HALF_UP) + " Velocity: " + BigDecimal(angularVelocity).setScale(2, BigDecimal.RoundingMode.HALF_UP) + "]"
|
override def toString = "NodeMechanical [" + connections.size() + " Torque: " + BigDecimal(torque).setScale(2, BigDecimal.RoundingMode.HALF_UP) + " Velocity: " + BigDecimal(angularVelocity).setScale(2, BigDecimal.RoundingMode.HALF_UP) + "]"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the torque of the mechanical device from a specific side
|
||||||
|
*
|
||||||
|
* @return force
|
||||||
|
*/
|
||||||
|
override def torque = _torque
|
||||||
|
|
||||||
|
def torque_=(newTorque: Double) = _torque = newTorque
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The class used to compare when making connections
|
* The class used to compare when making connections
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -10,7 +10,7 @@ import net.minecraftforge.common.util.ForgeDirection
|
||||||
*/
|
*/
|
||||||
class NodeGrinder(parent: TileGrindingWheel) extends NodeMechanical(parent: TileGrindingWheel)
|
class NodeGrinder(parent: TileGrindingWheel) extends NodeMechanical(parent: TileGrindingWheel)
|
||||||
{
|
{
|
||||||
override def getLoad = 1000d * Math.abs(angularVelocity)
|
override def inertia = 1000d * Math.abs(angularVelocity)
|
||||||
|
|
||||||
override def canConnect[B <: NodeMechanical](other: B, from: ForgeDirection): Boolean = parent.getDirection == from || parent.getDirection.getOpposite == from
|
override def canConnect[B <: NodeMechanical](other: B, from: ForgeDirection): Boolean = parent.getDirection == from || parent.getDirection.getOpposite == from
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ class NodeTurbine(parent: TileTurbine) extends NodeMechanical(parent)
|
||||||
* The mechanical load
|
* The mechanical load
|
||||||
* @return Torque in Newton meters per second
|
* @return Torque in Newton meters per second
|
||||||
*/
|
*/
|
||||||
override def getLoad = 100 * parent.multiBlockRadius * parent.multiBlockRadius
|
override def inertia = 100 * parent.multiBlockRadius * parent.multiBlockRadius
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Moment of inertia = m * r * r
|
* Moment of inertia = m * r * r
|
||||||
|
|
Loading…
Reference in a new issue