SHOW:
|
|
- or go back to the newest paste.
| 1 | - | --Automated Train Control v1 by Gazer29 |
| 1 | + | --Automated Cruise Control v2 by Gazer29 |
| 2 | --Uses Automation mod version: Beta 1 | |
| 3 | ||
| 4 | local component = require("component")
| |
| 5 | local term = require ("term")
| |
| 6 | local entity = component.entity_link.getAPI("immersiverailroading:locomotivediesel")
| |
| 7 | local thread = require("thread")
| |
| 8 | require("PIDController")
| |
| 9 | local serial = require("serialization")
| |
| 10 | local fs = require("filesystem")
| |
| 11 | local glassesTerminal = require("component").glasses
| |
| 12 | local event = require("event")
| |
| 13 | ||
| 14 | local ATC = false | |
| 15 | local RUNNING = true | |
| 16 | local MODE = 0 -- 0 SET, 1 RAMP, | |
| 17 | local sleep = 1 -- seconds | |
| 18 | local display = false | |
| 19 | local iteration = 1 | |
| 20 | local timer = nil | |
| 21 | ||
| 22 | local CONFIG_FILE = "/home/Waypoints.cfg" | |
| 23 | local CONFIG = nil | |
| 24 | local DEFAULT_CONFIG = {
| |
| 25 | array = {
| |
| 26 | {
| |
| 27 | waypoint = "Station 1", | |
| 28 | speed = 0, | |
| 29 | radius = 10, | |
| 30 | x = 1180, | |
| 31 | z = -333, | |
| 32 | mode = "wait", | |
| 33 | data = 20 | |
| 34 | }, | |
| 35 | {
| |
| 36 | waypoint = "Waypoint 2", | |
| 37 | speed = 10, | |
| 38 | radius = 10, | |
| 39 | x = 1180, | |
| 40 | z = -333, | |
| 41 | mode = nil, | |
| 42 | data = nil | |
| 43 | }, | |
| 44 | {
| |
| 45 | waypoint = "Waypoint 3", | |
| 46 | speed = 5, | |
| 47 | radius = 10, | |
| 48 | x = 1136, | |
| 49 | z = -333, | |
| 50 | mode = nil, | |
| 51 | data = nil | |
| 52 | } | |
| 53 | } | |
| 54 | } | |
| 55 | ||
| 56 | glassesTerminal.removeAll() | |
| 57 | atext = glassesTerminal.addText2D() | |
| 58 | atext.setText("ATC: OFF") -- no modifier!
| |
| 59 | atext.setFontSize(42) | |
| 60 | atext.addColor(1, 0, 0, 1) | |
| 61 | atext.setCondition(atext.addColor(0, 1, 0, 1), "OVERLAY_ACTIVE", true) | |
| 62 | ||
| 63 | btext = glassesTerminal.addText2D() | |
| 64 | btext.setText("+10")
| |
| 65 | btext.setFontSize(60) | |
| 66 | btext.addColor(1,0,0,1) | |
| 67 | btext.addTranslation(0, 10, 0) | |
| 68 | btext.setCondition(btext.addColor(0, 1, 0, 1), "OVERLAY_ACTIVE", true) | |
| 69 | ||
| 70 | ctext = glassesTerminal.addText2D() | |
| 71 | ctext.setText("-10")
| |
| 72 | ctext.setFontSize(60) | |
| 73 | ctext.addColor(1,0,0,1) | |
| 74 | ctext.addTranslation(0,18,0) | |
| 75 | ctext.setCondition(ctext.addColor(0, 1, 0, 1), "OVERLAY_ACTIVE", true) | |
| 76 | ||
| 77 | local function saveConfig(file, cfg) -- Adapted from HandieAndy's code | |
| 78 | local f = io.open(file, "w") | |
| 79 | if f == nil then error("Couldn't open " .. file .. " to write config.") end
| |
| 80 | f:write(serial.serialize(cfg, 100000)) | |
| 81 | f:close() | |
| 82 | print("Saved to file: ", CONFIG_FILE)
| |
| 83 | end | |
| 84 | ||
| 85 | local function loadConfig() -- Adapted from HandieAndy's code | |
| 86 | local f = io.open(CONFIG_FILE, "r") | |
| 87 | if f == nil then | |
| 88 | print("Could not open " .. CONFIG_FILE .. ".")
| |
| 89 | print("Loading default config")
| |
| 90 | saveConfig(CONFIG_FILE, DEFAULT_CONFIG) | |
| 91 | return DEFAULT_CONFIG | |
| 92 | else | |
| 93 | local config = serial.unserialize(f:read("*a"))
| |
| 94 | f:close() | |
| 95 | return config | |
| 96 | end | |
| 97 | end | |
| 98 | ||
| 99 | function helpdisplay() | |
| 100 | print("AutomaticTrainControl v1")
| |
| 101 | print("Commands:")
| |
| 102 | print("'Any number' - Changes set speed")
| |
| 103 | print("'+' - Displays additional information")
| |
| 104 | print("'-' - Hides additional information")
| |
| 105 | print("'ramp' - Changes to ramp mode, requires further input")
| |
| 106 | print("'idle' - Pauses train control")
| |
| 107 | print("'save' - Saves config file")
| |
| 108 | print("'stop' - Ends program")
| |
| 109 | end | |
| 110 | ||
| 111 | function GetTrainPos() | |
| 112 | positions = entity.getLocation() | |
| 113 | xpos = positions.getX() | |
| 114 | ypos = positions.getY() | |
| 115 | zpos = positions.getZ() | |
| 116 | print("X: ", xpos)
| |
| 117 | print("Z: ", zpos)
| |
| 118 | end | |
| 119 | ||
| 120 | function GetTrainSpeed() | |
| 121 | speed = entity.getCurrentSpeed() | |
| 122 | return speed | |
| 123 | end | |
| 124 | ||
| 125 | function setThrottle(x) | |
| 126 | if 0 >= x then x = 0 end | |
| 127 | if 1 <= x then x = 1 end | |
| 128 | entity.setThrottleLevel(x) | |
| 129 | if display then | |
| 130 | print("Throttle: ", x)
| |
| 131 | end | |
| 132 | end | |
| 133 | ||
| 134 | function setBrake(x) | |
| 135 | if 0 >= x then x = 0 end | |
| 136 | if 1 <= x then x = 1 end | |
| 137 | entity.setAirBrakeLevel(x) | |
| 138 | if display then | |
| 139 | print("Brake: ", x)
| |
| 140 | end | |
| 141 | end | |
| 142 | ||
| 143 | local function reads() | |
| 144 | while RUNNING do | |
| 145 | user = nil | |
| 146 | user = io.read() | |
| 147 | if user == "stop" then | |
| 148 | print("STOPPING...")
| |
| 149 | os.sleep(1) | |
| 150 | stop() | |
| 151 | end | |
| 152 | if user == "." then | |
| 153 | term.clear() | |
| 154 | end | |
| 155 | if user == "idle" then | |
| 156 | MODE = 2 | |
| 157 | end | |
| 158 | if user == "ramp" then | |
| 159 | print("Start Speed (type 'x' for current setpoint):")
| |
| 160 | c = io.read() | |
| 161 | if c == "x" then | |
| 162 | c = setpoint | |
| 163 | end | |
| 164 | print("End Speed:")
| |
| 165 | rampStart = c | |
| 166 | c = io.read() | |
| 167 | print("Ramp Time (seconds):")
| |
| 168 | rampEnd = c | |
| 169 | c = io.read() | |
| 170 | rampTime = c | |
| 171 | rampDiff = rampEnd - rampStart | |
| 172 | rampCount = math.floor(rampTime/sleep) | |
| 173 | rampInc = rampDiff / rampCount | |
| 174 | PID:SetPoint(rampStart) | |
| 175 | setpoint = rampStart | |
| 176 | MODE = 1 | |
| 177 | end | |
| 178 | if user == "+" then | |
| 179 | display = true | |
| 180 | term.clear() | |
| 181 | end | |
| 182 | if user == "save" then | |
| 183 | saveConfig(CONFIG_FILE, CONFIG) | |
| 184 | end | |
| 185 | if user == "-" then | |
| 186 | display = false | |
| 187 | term.clear() | |
| 188 | os.sleep(1) | |
| 189 | helpdisplay() | |
| 190 | end | |
| 191 | if nil ~= tonumber(user) then | |
| 192 | MODE = 0 | |
| 193 | PID:SetPoint(user) | |
| 194 | setpoint = user | |
| 195 | print("Setting Speed: ", user)
| |
| 196 | end | |
| 197 | os.sleep(1) | |
| 198 | end | |
| 199 | end | |
| 200 | ||
| 201 | -- run through array | |
| 202 | function getDistance() | |
| 203 | --active = CONFIG.array[iteration] | |
| 204 | x1 = active.x | |
| 205 | z1 = active.z | |
| 206 | positions = entity.getLocation() | |
| 207 | y1 = positions.getY() | |
| 208 | x = positions.getDistanceToCoordinates(x1,y1,z1) | |
| 209 | return x | |
| 210 | end | |
| 211 | ||
| 212 | ||
| 213 | local function main() | |
| 214 | while RUNNING do | |
| 215 | array = CONFIG.array | |
| 216 | active = CONFIG.array[iteration] | |
| 217 | distance = getDistance() | |
| 218 | if distance < active.radius or timer ~= nil then | |
| 219 | setpoint = active.speed | |
| 220 | PID:SetPoint(setpoint) | |
| 221 | if active.mode == "wait" then | |
| 222 | if timer == nil then | |
| 223 | timer = active.data | |
| 224 | end | |
| 225 | if timer > 0 then | |
| 226 | timer = timer - 1 | |
| 227 | else | |
| 228 | timer = nil | |
| 229 | if iteration >= #array then | |
| 230 | iteration = 1 | |
| 231 | else | |
| 232 | iteration = iteration + 1 | |
| 233 | end | |
| 234 | end | |
| 235 | else | |
| 236 | if iteration >= #array then | |
| 237 | iteration = 1 | |
| 238 | else | |
| 239 | iteration = iteration + 1 | |
| 240 | end | |
| 241 | end | |
| 242 | end | |
| 243 | ||
| 244 | input = GetTrainSpeed() | |
| 245 | if MODE ~= 2 then | |
| 246 | if MODE == 1 then | |
| 247 | if rampCount > 0 then | |
| 248 | rampCount = rampCount - 1 | |
| 249 | setpoint = setpoint + rampInc | |
| 250 | PID:SetPoint(setpoint) | |
| 251 | if rampCount == 0 then | |
| 252 | setpoint = rampEnd | |
| 253 | PID:SetPoint(rampEnd) | |
| 254 | end | |
| 255 | else | |
| 256 | Mode = 0 | |
| 257 | end | |
| 258 | end | |
| 259 | PID:SetInput(input) | |
| 260 | PID:Compute() | |
| 261 | output = PID:GetOutput() | |
| 262 | BrakeOut = output * -1 | |
| 263 | setThrottle(output) | |
| 264 | setBrake(BrakeOut) | |
| 265 | end | |
| 266 | if display then | |
| 267 | print("CurrentSpeed: ", input)
| |
| 268 | if MODE ~= 2 then | |
| 269 | print("SetPoint: ", setpoint)
| |
| 270 | end | |
| 271 | print("Waypoint: ",active.waypoint)
| |
| 272 | print("Distance: ",distance)
| |
| 273 | print("Timer: ",timer)
| |
| 274 | GetTrainPos() | |
| 275 | print("----")
| |
| 276 | os.sleep(sleep) | |
| 277 | term.clear() | |
| 278 | else | |
| 279 | os.sleep(sleep) | |
| 280 | end | |
| 281 | checkATC() | |
| 282 | end | |
| 283 | end | |
| 284 | ||
| 285 | function stop() | |
| 286 | RUNNING = false | |
| 287 | end | |
| 288 | ||
| 289 | function checkATC() | |
| 290 | if MODE == 0 then | |
| 291 | atext.setText("ATC: "..setpoint.." Speed: "..(math.floor(input * 1000)/1000))
| |
| 292 | ATC = true | |
| 293 | end | |
| 294 | if MODE == 2 then | |
| 295 | atext.setText("ATC: OFF")
| |
| 296 | ATC = false | |
| 297 | end | |
| 298 | end | |
| 299 | ||
| 300 | function inbounds(x0, y0, x1, y1, x2, y2) | |
| 301 | local output = false | |
| 302 | if x0 > x1 then | |
| 303 | if y0 > y1 then | |
| 304 | if x0 < x2 then | |
| 305 | if y0 < y2 then | |
| 306 | output = true | |
| 307 | end | |
| 308 | end | |
| 309 | end | |
| 310 | end | |
| 311 | return output | |
| 312 | end | |
| 313 | ||
| 314 | function pullOverlay() | |
| 315 | while RUNNING do | |
| 316 | EVENT, ID, USER, X, Y, BUTTON = event.pull("interact_overlay")
| |
| 317 | if inbounds(X,Y,0,0,41,7) then | |
| 318 | if ATC == true then | |
| 319 | MODE = 2 | |
| 320 | else | |
| 321 | MODE = 0 | |
| 322 | PID:SetPoint(setpoint) | |
| 323 | end | |
| 324 | elseif inbounds(X,Y,0,11,20,16) then | |
| 325 | setpoint = setpoint + 10 | |
| 326 | PID:SetPoint(setpoint) | |
| 327 | elseif inbounds(X,Y,0,19,20,24) then | |
| 328 | setpoint = setpoint - 10 | |
| 329 | PID:SetPoint(setpoint) | |
| 330 | end | |
| 331 | end | |
| 332 | end | |
| 333 | ||
| 334 | ----------- Main loop ------------ | |
| 335 | ||
| 336 | term.clear() | |
| 337 | CONFIG = loadConfig() | |
| 338 | setpoint = 0 | |
| 339 | PID:new(0.01, 0.5, 0.0001, 0) | |
| 340 | PID:SetInput((GetTrainSpeed())) | |
| 341 | PID:SetOutput(0) | |
| 342 | PID:SetPoint(setpoint) | |
| 343 | PID:SetOutputLimits(-1, 1) | |
| 344 | PID:SetMode(1) | |
| 345 | ||
| 346 | helpdisplay() | |
| 347 | ||
| 348 | local tb = thread.create(main) | |
| 349 | local ta = thread.create(reads) | |
| 350 | local tc = thread.create(pullOverlay) | |
| 351 | tb:join() | |
| 352 | ta:join() | |
| 353 | tc:join() | |
| 354 | term.clear() |