SHARE
TWEET

Drone OS Thing

osmarks May 26th, 2020 (edited) 966 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. local drone = component.proxy(component.list "drone"())
  2. local net = component.proxy(component.list "internet"())
  3. local wlan = component.proxy(component.list "modem"())
  4. local comp = component.proxy(component.list "computer"())
  5. wlan.setWakeMessage("poweron", true)
  6.  
  7. local central_point = { x = 297, y = 80, z = 294 }
  8.  
  9. local statuses = {
  10.     loading = { text = "LOAD", color = 0x000000 },
  11.     moving = { text = "GO", color = 0xFFFF00 },
  12.     idle = { text = "IDLE", color = 0x00FFFF },
  13.     error = { text = "ERROR", color = 0xFF0000 },
  14.     low_battery = { text = "ELOW", 0xFF8800 }
  15. }
  16.  
  17. local function set_status(status)
  18.     local stat = statuses[status]
  19.     drone.setLightColor(stat.color or 0xFFFFFF)
  20.     drone.setStatusText((stat.text or status) .. (" "):rep(8))
  21. end
  22.  
  23. set_status "loading"
  24. comp.beep(600, 1)
  25.  
  26. local function energy()
  27.     return computer.energy() / computer.maxEnergy()
  28. end
  29.  
  30. local GPS_PING_CHANNEL, GPS_RESPONSE_CHANNEL, TIMEOUT = 2048, 2047, 1
  31.  
  32. wlan.setStrength(math.huge)
  33.  
  34. local function fetch(url)
  35.     local res, err = net.request(url)
  36.     if not res then error(url .. " error: " .. err) end
  37.     local out = {}
  38.     while true do
  39.         local chunk, err = res.read()
  40.         if err then error(url .. " error: " .. err) end
  41.         if chunk then table.insert(out, chunk)
  42.         else return table.concat(out) end
  43.     end
  44. end
  45.  
  46. local function round(v, m)
  47.     m = m or 1.0
  48.     return {
  49.         x = math.floor((v.x+(m*0.5))/m)*m,
  50.         y = math.floor((v.y+(m*0.5))/m)*m,
  51.         z = math.floor((v.z+(m*0.5))/m)*m
  52.     }
  53. end
  54.  
  55. local function len(v)
  56.     return math.sqrt(v.x^2 + v.y^2 + v.z^2)
  57. end
  58.  
  59. local function cross(v, b)
  60.     return {x = v.y*b.z-v.z*b.y, y = v.z*b.x-v.x*b.z, z = v.x*b.y-v.y*b.x}
  61. end
  62.  
  63. local function dot(v, b)
  64.     return v.x*b.x + v.y*b.y + v.z*b.z
  65. end
  66.  
  67. local function add(v, b)
  68.     return {x = v.x+b.x, y = v.y+b.y, z = v.z+b.z}
  69. end
  70.  
  71. local function sub(v, b)
  72.     return {x = v.x-b.x, y = v.y-b.y, z = v.z-b.z}
  73. end
  74.  
  75. local function mul(v, m)
  76.     return {x = v.x*m, y = v.y*m, z = v.z*m}
  77. end
  78.  
  79. local function norm(v)
  80.     return mul(v, 1/len(v))
  81. end
  82.  
  83. local function trilaterate(A, B, C)
  84.     local a2b = {x = B.x-A.x, y = B.y-A.y, z = B.z-A.z}
  85.     local a2c = {x = C.x-A.x, y = C.y-A.y, z = C.z-A.z}
  86.     if math.abs(dot(norm(a2b), norm(a2c))) > 0.999 then
  87.         return nil
  88.     end
  89.     local d = len(a2b)
  90.     local ex = norm(a2b)
  91.     local i = dot(ex, a2c)
  92.     local ey = norm(sub(mul(ex, i), a2c))
  93.     local j = dot(ey, a2c)
  94.     local ez = cross(ex, ey)
  95.     local r1 = A.d
  96.     local r2 = B.d
  97.     local r3 = C.d
  98.     local x = (r1^2 - r2^2 + d^2) / (2*d)
  99.     local y = (r1^2 - r3^2 - x^2 + (x-i)^2 + j^2) / (2*j)
  100.     local result = add(A, add(mul(ex, x), mul(ey, y)))
  101.     local zSquared = r1^2 - x^2 - y^2
  102.     if zSquared > 0 then
  103.         local z = math.sqrt(zSquared)
  104.         local result1 = add(result, mul(ez, z))
  105.         local result2 = add(result, mul(ez, z))
  106.         local rounded1, rounded2 = round(result1, 0.01), round(result2, 0.01)
  107.         if rounded1.x ~= rounded2.x or
  108.              rounded1.y ~= rounded2.y or
  109.              rounded1.z ~= rounded2.z then
  110.             return rounded1, rounded2
  111.         else
  112.             return rounded1
  113.         end
  114.     end
  115.     return round(result, 0.01)
  116. end
  117.  
  118. local function narrow(p1, p2, fix)
  119.     local dist1 = math.abs(len(sub(p1, fix)) - fix.d)
  120.     local dist2 = math.abs(len(sub(p2, fix)) - fix.d)
  121.     if math.abs(dist1 - dist2) < 0.01 then
  122.         return p1, p2
  123.     elseif dist1 < dist2 then
  124.         return round(p1, 0.01)
  125.     else
  126.         return round(p2, 0.01)
  127.     end
  128. end
  129.  
  130. local function locate(timeout)
  131.     local timeout = timeout or TIMEOUT
  132.     wlan.open(GPS_RESPONSE_CHANNEL)
  133.     wlan.broadcast(GPS_PING_CHANNEL, "PING")
  134.     local fixes = {}
  135.     local pos1, pos2 = nil, nil
  136.     local deadline = computer.uptime() + timeout
  137.     local dim
  138.     repeat
  139.         local event, _, from, port, distance, x, y, z, dimension = computer.pullSignal(deadline - computer.uptime())
  140.         if event == "modem_message" and port == GPS_RESPONSE_CHANNEL and x and y and z then
  141.             if type(dim) == "string" then dim = dimension end
  142.             local fix = {x = x, y = y, z = z, d = distance}
  143.             if fix.d == 0 then
  144.                 pos1, pos2 = {fix.x, fix.y, fix.z}, nil
  145.             else
  146.                 table.insert(fixes, fix)
  147.                 if #fixes >= 3 then
  148.                     if not pos1 then
  149.                         pos1, pos2 = trilaterate(fixes[1], fixes[2], fixes[#fixes])
  150.                     else
  151.                         pos1, pos2 = narrow(pos1, pos2, fixes[#fixes])
  152.                     end
  153.                 end            
  154.             end
  155.             if pos1 and not pos2 then
  156.                 break
  157.             end
  158.         end
  159.     until computer.uptime() >= deadline
  160.     wlan.close(GPS_RESPONSE_CHANNEL)
  161.     if pos1 and pos2 then
  162.         return nil
  163.     elseif pos1 then
  164.         return pos1, dim
  165.     else
  166.         return nil
  167.     end
  168. end
  169.  
  170. local a={["\\"]="\\\\",["\""]="\\\"",["\b"]="\\b",["\f"]="\\f",["\n"]="\\n",["\r"]="\\r",["\t"]="\\t"}local b={["\\/"]="/"}for c,d in pairs(a)do b[d]=c end;local e;local function f(...)local g={}for h=1,select("#",...)do g[select(h,...)]=true end;return g end;local i=f(" ","\t","\r","\n")local j=f(" ","\t","\r","\n","]","}",",")local k=f("\\","/",'"',"b","f","n","r","t","u")local l=f("true","false","null")local m={["true"]=true,["false"]=false,["null"]=nil}local function n(o,p,q,r)for h=p,#o do if q[o:sub(h,h)]~=r then return h end end;return#o+1 end;local function s(o,p,t)local u=1;local v=1;for h=1,p-1 do v=v+1;if o:sub(h,h)=="\n"then u=u+1;v=1 end end;error(string.format("%s at line %d col %d",t,u,v))end;local function w(x)local y=math.floor;if x<=0x7f then return string.char(x)elseif x<=0x7ff then return string.char(y(x/64)+192,x%64+128)elseif x<=0xffff then return string.char(y(x/4096)+224,y(x%4096/64)+128,x%64+128)elseif x<=0x10ffff then return string.char(y(x/262144)+240,y(x%262144/4096)+128,y(x%4096/64)+128,x%64+128)end;error(string.format("invalid unicode codepoint '%x'",x))end;local function z(A)local B=tonumber(A:sub(3,6),16)local C=tonumber(A:sub(9,12),16)if C then return w((B-0xd800)*0x400+C-0xdc00+0x10000)else return w(B)end end;local function D(o,h)local E=false;local F=false;local G=false;local H;for I=h+1,#o do local J=o:byte(I)if J<32 then s(o,I,"control character in string")end;if H==92 then if J==117 then local K=o:sub(I+1,I+5)if not K:find("%x%x%x%x")then s(o,I,"invalid unicode escape in string")end;if K:find("^[dD][89aAbB]")then F=true else E=true end else local L=string.char(J)if not k[L]then s(o,I,"invalid escape char '"..L.."' in string")end;G=true end;H=nil elseif J==34 then local A=o:sub(h+1,I-1)if F then A=A:gsub("\\u[dD][89aAbB]..\\u....",z)end;if E then A=A:gsub("\\u....",z)end;if G then A=A:gsub("\\.",b)end;return A,I+1 else H=J end end;s(o,h,"expected closing quote for string")end;local function M(o,h)local J=n(o,h,j)local A=o:sub(h,J-1)local x=tonumber(A)if not x then s(o,h,"invalid number '"..A.."'")end;return x,J end;local function N(o,h)local J=n(o,h,j)local O=o:sub(h,J-1)if not l[O]then s(o,h,"invalid literal '"..O.."'")end;return m[O],J end;local function P(o,h)local g={}local x=1;h=h+1;while 1 do local J;h=n(o,h,i,true)if o:sub(h,h)=="]"then h=h+1;break end;J,h=e(o,h)g[x]=J;x=x+1;h=n(o,h,i,true)local Q=o:sub(h,h)h=h+1;if Q=="]"then break end;if Q~=","then s(o,h,"expected ']' or ','")end end;return g,h end;local function R(o,h)local g={}h=h+1;while 1 do local S,T;h=n(o,h,i,true)if o:sub(h,h)=="}"then h=h+1;break end;if o:sub(h,h)~='"'then s(o,h,"expected string for key")end;S,h=e(o,h)h=n(o,h,i,true)if o:sub(h,h)~=":"then s(o,h,"expected ':' after key")end;h=n(o,h+1,i,true)T,h=e(o,h)g[S]=T;h=n(o,h,i,true)local Q=o:sub(h,h)h=h+1;if Q=="}"then break end;if Q~=","then s(o,h,"expected '}' or ','")end end;return g,h end;local U={['"']=D,["0"]=M,["1"]=M,["2"]=M,["3"]=M,["4"]=M,["5"]=M,["6"]=M,["7"]=M,["8"]=M,["9"]=M,["-"]=M,["t"]=N,["f"]=N,["n"]=N,["["]=P,["{"]=R}e=function(o,p)local Q=o:sub(p,p)local y=U[Q]if y then return y(o,p)end;s(o,p,"unexpected character '"..Q.."'")end;local function json_decode(o)if type(o)~="string"then error("expected argument of type string, got "..type(o))end;local g,p=e(o,n(o,1,i,true))p=n(o,p,i,true)if p<=#o then s(o,p,"trailing garbage")end;return g end
  171.  
  172. local function sleep(timeout)
  173.     local deadline = computer.uptime() + (timeout or 0)
  174.     repeat
  175.         computer.pullSignal(deadline - computer.uptime())
  176.     until computer.uptime() >= deadline
  177. end
  178.  
  179. local function moveraw(x, y, z)
  180.     set_status "moving"
  181.     drone.move(x, y, z)
  182.     repeat
  183.         sleep(0.5)
  184.     until drone.getVelocity() < 0.1
  185.     set_status "idle"
  186. end
  187.  
  188. local function move(pos)
  189.     moveraw(0, 32, 0)
  190.     moveraw(pos.x, pos.y, pos.z)
  191.     moveraw(0, -32, 0)
  192. end
  193.  
  194. local function follow(currpos)
  195.     local data = json_decode(fetch "https://dynmap.codersnet.pw/up/world/world/1588704574112")
  196.     local possibles = {}
  197.     for _, p in pairs(data.players) do
  198.         local plrpos = { x = p.x, y = p.y, z = p.z }
  199.         local dist = len(sub(plrpos, central_point))
  200.         if dist < 100 and p.world == "world" then
  201.             table.insert(possibles, plrpos)
  202.         end
  203.     end
  204.     if #possibles == 0 then return false, "TNF" end
  205.     local targpos = possibles[math.random(1, #possibles)]
  206.     local offset = sub(targpos, currpos)
  207.     comp.beep(400, 0.5)
  208.     move(offset)
  209.     return true
  210. end
  211.  
  212. while true do
  213.     set_status "idle"
  214.     local currpos = locate()
  215.     if currpos then
  216.         wlan.broadcast(1033, drone.name(), "LOC", currpos.x, currpos.y, currpos.z)
  217.         local offset_from_hub = sub(central_point, currpos)
  218.         if len(offset_from_hub) then
  219.             move(offset_from_hub)
  220.         else
  221.             local ok, err = follow(currpos)
  222.             if not ok then set_status "error" drone.setStatusText("E" .. err) sleep(10) end
  223.             sleep(1)
  224.         end
  225.     end
  226.     if energy() < 0.3 then
  227.         wlan.broadcast(1033, drone.name(), "LOW")
  228.         comp.beep(2000, 1.5)
  229.         status "low_battery"
  230.         move(sub(central_point, locate()))
  231.     end
  232. end
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
Top