TIMAS_Bro

Untitled

May 18th, 2026 (edited)
82
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.38 KB | None | 0 0
  1. local Stabilitron = {}
  2. Stabilitron.__index = Stabilitron
  3.  
  4. local pid = require ".pid"
  5. local ship = _G.sublevel
  6.  
  7. local function clamp(value, min, max)
  8. return math.min(max, math.max(value, min))
  9. end
  10.  
  11. local function normalizeAngle(angle)
  12. return ((angle + 180) % 360) - 180
  13. end
  14.  
  15. local function yawFromPose(pose)
  16. local w = pose.orientation.a
  17. local x = pose.orientation.v.x
  18. local y = pose.orientation.v.y
  19. local z = pose.orientation.v.z
  20. local sinyCosp = 2 * (w * y + x * z)
  21. local cosyCosp = 1 - 2 * (y * y + z * z)
  22. return math.deg(math.atan(sinyCosp, cosyCosp))
  23. end
  24.  
  25. function Stabilitron:new(autoAngleRight, autoAngleLeft, gimbal)
  26. local self = setmetatable({}, Stabilitron)
  27. self.autoAngleRight = autoAngleRight
  28. self.autoAngleLeft = autoAngleLeft
  29. self.gimbal = gimbal
  30.  
  31. self.pidPitch = pid:new(0.9, 0.0, 0.25, -10, 10)
  32. self.pidRoll = pid:new(0.55, 0.0, 0.12, -15, 15)
  33.  
  34. self.targetPitch = 0
  35. self.baseTrim = 12
  36. self.rollGain = 1
  37. self.targetX = 0
  38. self.targetZ = 0
  39. self.arrivalRadius = 8
  40. self.maxBank = 5
  41. self.headingToRoll = 0.04
  42. self.velocityLookahead = 0.6
  43. self.bankLiftComp = 0.12
  44. self.minCollective = 10
  45. self.pitchCmdLimit = 6
  46. self.rollRecoverAngle = 15
  47. self.maxDifferential = 12
  48. self.airframeDifferentialTrim = 1.5
  49. self.lastX = nil
  50. self.lastZ = nil
  51. self.lastTime = nil
  52. self.debugDistance = 0
  53. self.debugHeadingError = 0
  54. self.debugTargetRoll = 0
  55. self.debugYaw = 0
  56.  
  57. return self
  58. end
  59.  
  60. function Stabilitron:drawGraph(y, label, val, minV, maxV, color)
  61. local w = term.getSize()
  62. local graphW = w - 15
  63. local range = maxV - minV
  64. local normalized = (val - minV) / range
  65. local dotX = math.floor(12 + normalized * graphW)
  66. dotX = clamp(dotX, 12, w - 4)
  67.  
  68. term.setCursorPos(1, y)
  69. term.setTextColor(colors.white)
  70. term.write(string.format("%-6s", label))
  71. term.setCursorPos(12, y)
  72. term.setTextColor(colors.gray)
  73. term.write(string.rep("-", graphW))
  74. term.setCursorPos(dotX, y)
  75. term.setTextColor(color)
  76. term.write("O")
  77. term.setCursorPos(w - 4, y)
  78. term.setTextColor(colors.white)
  79. term.write(string.format("%4.0f", val))
  80. end
  81.  
  82. function Stabilitron:update()
  83. while true do
  84. local pose = ship and ship.getLogicalPose and ship.getLogicalPose()
  85. if pose then
  86. local now = os.clock()
  87. local curX = pose.position.x
  88. local curZ = pose.position.z
  89. local angles = self.gimbal.getAngles()
  90. local currentPitch = angles[1]
  91. local currentRoll = angles[2]
  92. local yaw = yawFromPose(pose)
  93. local velX = 0
  94. local velZ = 0
  95.  
  96. if self.lastX and self.lastZ and self.lastTime then
  97. local dt = now - self.lastTime
  98. if dt > 0 then
  99. velX = (curX - self.lastX) / dt
  100. velZ = (curZ - self.lastZ) / dt
  101. end
  102. end
  103.  
  104. self.lastX = curX
  105. self.lastZ = curZ
  106. self.lastTime = now
  107.  
  108. local dx = self.targetX - curX
  109. local dz = self.targetZ - curZ
  110. local distance = math.sqrt(dx * dx + dz * dz)
  111. local targetRoll = 0
  112. local headingError = 0
  113.  
  114. if distance > self.arrivalRadius then
  115. local aimX = self.targetX - velX * self.velocityLookahead
  116. local aimZ = self.targetZ - velZ * self.velocityLookahead
  117. local aimDx = aimX - curX
  118. local aimDz = aimZ - curZ
  119. local aimDistance = math.sqrt(aimDx * aimDx + aimDz * aimDz)
  120.  
  121. if aimDistance > 0.001 then
  122. local desiredHeading = math.deg(math.atan(aimDx, aimDz))
  123. headingError = normalizeAngle(desiredHeading - yaw)
  124. targetRoll = clamp(-headingError * self.headingToRoll, -self.maxBank, self.maxBank)
  125. end
  126. end
  127.  
  128. if math.abs(currentRoll) > self.rollRecoverAngle then
  129. targetRoll = 0
  130. end
  131.  
  132. local pitchCmd = self.pidPitch:compute(self.targetPitch, currentPitch, 0.05)
  133. local rollCmd = self.pidRoll:compute(targetRoll, currentRoll, 0.05)
  134.  
  135. local bankComp = math.abs(currentRoll) * self.bankLiftComp
  136. local pitchCorrection = clamp(pitchCmd, -self.pitchCmdLimit, self.pitchCmdLimit)
  137. local collective = clamp(
  138. self.baseTrim + bankComp + pitchCorrection,
  139. self.minCollective,
  140. 40
  141. )
  142. local differential = clamp(
  143. -rollCmd * self.rollGain + self.airframeDifferentialTrim,
  144. -self.maxDifferential,
  145. self.maxDifferential
  146. )
  147.  
  148. local lOut = clamp(collective - differential, -40, 40)
  149. local rOut = clamp(collective + differential, -40, 40)
  150.  
  151. self.debugDistance = distance
  152. self.debugHeadingError = headingError
  153. self.debugTargetRoll = targetRoll
  154. self.debugYaw = yaw
  155.  
  156. self.autoAngleLeft:setAngle(lOut)
  157. self.autoAngleRight:setAngle(rOut)
  158.  
  159. term.clear()
  160. term.setCursorPos(1, 1)
  161. term.setTextColor(colors.yellow)
  162. print("--- STABILITRON ---")
  163.  
  164. self:drawGraph(3, "PITCH", currentPitch, -90, 90, colors.red)
  165. self:drawGraph(4, "ROLL ", currentRoll, -45, 45, colors.blue)
  166. self:drawGraph(5, "TRIM ", self.baseTrim, -40, 40, colors.orange)
  167. self:drawGraph(7, "OUT_L", lOut, -40, 40, colors.green)
  168. self:drawGraph(8, "OUT_R", rOut, -40, 40, colors.green)
  169.  
  170. term.setCursorPos(1, 10)
  171. term.setTextColor(colors.lightGray)
  172. print(string.format("ERR_P : %.2f", self.targetPitch - currentPitch))
  173. print(string.format("P_CMD : %.2f", pitchCmd))
  174. print(string.format("R_CMD : %.2f", rollCmd))
  175. print(string.format("COLL : %.2f", collective))
  176. print(string.format("DIST : %.1f", self.debugDistance))
  177. print(string.format("YAW_E : %.2f", self.debugHeadingError))
  178. print(string.format("T_ROL : %.2f", self.debugTargetRoll))
  179. end
  180.  
  181. sleep(0.05)
  182. end
  183. end
  184.  
  185. return Stabilitron
  186.  
Advertisement
Add Comment
Please, Sign In to add comment