Friendsincode

Handheld Remote Control Program

Mar 21st, 2025 (edited)
399
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. --------------------------------------------------------------------------------
  2. -- Wireless Robot Control Program (Handheld) with Configuration UI
  3. --
  4. -- This program runs on your handheld remote computer. It:
  5. --
  6. -- 1. Listens for robots to check in (they send "checkin:<name>").
  7. -- 2. Displays a main list of robots as colored buttons.
  8. -- 3. When a robot button is touched, shows a submenu with options:
  9. --      Stats, Start, Stop, Home, Config.
  10. -- 4. The Stats option sends "stats" and waits for a reply.
  11. -- 5. The Config option brings up a configuration screen that lets you
  12. --     adjust the mine width, mine height, and starting facing direction.
  13. --     (Facing: 0=East, 1=South, 2=West, 3=North.)
  14. -- 6. The configuration is sent to the robot in the format:
  15. --     "config:<width>:<height>:<facing>"
  16. --
  17. -- Press 'r' to refresh the robot list.
  18. --------------------------------------------------------------------------------
  19.  
  20. -- Open rednet on the modem on the specified side.
  21. local modemSide = "back"
  22. if not rednet.isOpen(modemSide) then
  23.   rednet.open(modemSide)
  24. end
  25.  
  26. local robots = {}  -- key: robot ID, value: {name, lastCheckin}
  27.  
  28. --------------------------------------------------------------------------------
  29. -- Helper: Draw Button
  30. --------------------------------------------------------------------------------
  31. local function drawButton(button)
  32.   term.setBackgroundColor(button.bgColor)
  33.   term.setTextColor(button.textColor)
  34.   for y = button.y1, button.y2 do
  35.     term.setCursorPos(button.x1, y)
  36.     term.write(string.rep(" ", button.x2 - button.x1 + 1))
  37.   end
  38.   local textLength = #button.text
  39.   local btnWidth = button.x2 - button.x1 + 1
  40.   local startX = button.x1 + math.floor((btnWidth - textLength) / 2)
  41.   local centerY = math.floor((button.y1 + button.y2) / 2)
  42.   term.setCursorPos(startX, centerY)
  43.   term.write(button.text)
  44. end
  45.  
  46. local function inButton(x, y, button)
  47.   return x >= button.x1 and x <= button.x2 and y >= button.y1 and y <= button.y2
  48. end
  49.  
  50. --------------------------------------------------------------------------------
  51. -- Rednet Check-In Listener
  52. --------------------------------------------------------------------------------
  53. local function handleRednetMessages()
  54.   while true do
  55.     local sender, message, protocol = rednet.receive()
  56.     if type(message) == "string" then
  57.       local cmd, data = message:match("^(%w+):?(.*)")
  58.       if cmd == "checkin" then
  59.         local name = (data ~= "" and data) or ("Robot " .. sender)
  60.         robots[sender] = { name = name, lastCheckin = os.time() }
  61.         print("Robot checked in: " .. sender .. " (" .. name .. ")")
  62.       end
  63.     end
  64.   end
  65. end
  66.  
  67. --------------------------------------------------------------------------------
  68. -- Draw Main List of Robots as Buttons
  69. --------------------------------------------------------------------------------
  70. local function drawMainList()
  71.   term.clear()
  72.   term.setCursorPos(1,1)
  73.   term.setBackgroundColor(colors.black)
  74.   term.setTextColor(colors.white)
  75.   print("Robot Control Main List (touch a robot)")
  76.   print("Press 'r' to refresh")
  77.   local btns = {}
  78.   local btnY = 4
  79.   local btnHeight = 3
  80.   local btnMargin = 1
  81.   local index = 1
  82.   for id, info in pairs(robots) do
  83.     local btn = {
  84.       x1 = 2,
  85.       y1 = btnY,
  86.       x2 = term.getSize() - 2,
  87.       y2 = btnY + btnHeight - 1,
  88.       bgColor = colors.blue,
  89.       textColor = colors.white,
  90.       text = info.name .. " (ID:" .. id .. ")"
  91.     }
  92.     drawButton(btn)
  93.     btns[index] = { id = id, btn = btn }
  94.     btnY = btnY + btnHeight + btnMargin
  95.     index = index + 1
  96.   end
  97.   return btns
  98. end
  99.  
  100. --------------------------------------------------------------------------------
  101. -- Draw Submenu for a Selected Robot (Stats, Start, Stop, Home, Config)
  102. --------------------------------------------------------------------------------
  103. local function drawRobotMenu(robotId)
  104.   term.clear()
  105.   term.setCursorPos(1,1)
  106.   term.setBackgroundColor(colors.black)
  107.   term.setTextColor(colors.white)
  108.   local robot = robots[robotId]
  109.   print("Robot: " .. robot.name .. " (ID:" .. robotId .. ")")
  110.   print("Select a command:")
  111.   local btnWidth = math.floor((term.getSize() - 6) / 2)
  112.   local btnHeight = 3
  113.   local startX = 2
  114.   local startY = 4
  115.   local cmds = {
  116.     {text="Stats", cmd="stats", bgColor=colors.lime},
  117.     {text="Start", cmd="start", bgColor=colors.green},
  118.     {text="Stop",  cmd="stop",  bgColor=colors.red},
  119.     {text="Home",  cmd="home",  bgColor=colors.orange},
  120.     {text="Config", cmd="config", bgColor=colors.cyan}
  121.   }
  122.   local btns = {}
  123.   for i = 1, #cmds do
  124.     local col = ((i - 1) % 2)
  125.     local row = math.floor((i - 1) / 2)
  126.     local btn = {
  127.       x1 = startX + col * (btnWidth + 2),
  128.       y1 = startY + row * (btnHeight + 1),
  129.       x2 = startX + col * (btnWidth + 2) + btnWidth - 1,
  130.       y2 = startY + row * (btnHeight + 1) + btnHeight - 1,
  131.       bgColor = cmds[i].bgColor,
  132.       textColor = colors.white,
  133.       text = cmds[i].text
  134.     }
  135.     drawButton(btn)
  136.     btns[i] = { cmd = cmds[i].cmd, btn = btn }
  137.   end
  138.   local backBtn = {
  139.     x1 = 2,
  140.     y1 = term.getSize() - 3,
  141.     x2 = term.getSize() - 2,
  142.     y2 = term.getSize() - 1,
  143.     bgColor = colors.gray,
  144.     textColor = colors.white,
  145.     text = "Back"
  146.   }
  147.   drawButton(backBtn)
  148.   btns[#cmds+1] = { cmd = "back", btn = backBtn }
  149.   return btns
  150. end
  151.  
  152. --------------------------------------------------------------------------------
  153. -- Configuration UI for a Robot
  154. -- Allows setting mine width, height, and starting facing direction.
  155. --------------------------------------------------------------------------------
  156. local function configureRobot(robotId)
  157.   local configWidth = 16
  158.   local configHeight = 16
  159.   local configFacing = 0  -- 0=East, 1=South, 2=West, 3=North
  160.   local directions = {"East", "South", "West", "North"}
  161.  
  162.   local function redrawConfig()
  163.     term.clear()
  164.     term.setCursorPos(1,1)
  165.     print("Configure Robot " .. robotId)
  166.     print("---------------------")
  167.     print("Mine Width: " .. configWidth)
  168.     print("Mine Height: " .. configHeight)
  169.     print("Facing: " .. directions[configFacing+1])
  170.   end
  171.  
  172.   redrawConfig()
  173.   -- We'll use a simple loop waiting for key presses to adjust values.
  174.   -- For touch, we define colored buttons.
  175.   local btns = {}
  176.   local screenWidth, screenHeight = term.getSize()
  177.   -- Define buttons for width (- and +)
  178.   btns[1] = {cmd="wdec", btn = {x1=2, y1=6, x2=12, y2=8, bgColor=colors.red, textColor=colors.white, text="- Width"}}
  179.   btns[2] = {cmd="winc", btn = {x1=14, y1=6, x2=screenWidth-2, y2=8, bgColor=colors.green, textColor=colors.white, text="+ Width"}}
  180.   -- Buttons for height
  181.   btns[3] = {cmd="hdec", btn = {x1=2, y1=9, x2=12, y2=11, bgColor=colors.red, textColor=colors.white, text="- Height"}}
  182.   btns[4] = {cmd="hinc", btn = {x1=14, y1=9, x2=screenWidth-2, y2=11, bgColor=colors.green, textColor=colors.white, text="+ Height"}}
  183.   -- Buttons for facing
  184.   btns[5] = {cmd="fdec", btn = {x1=2, y1=12, x2=12, y2=14, bgColor=colors.red, textColor=colors.white, text="- Facing"}}
  185.   btns[6] = {cmd="finc", btn = {x1=14, y1=12, x2=screenWidth-2, y2=14, bgColor=colors.green, textColor=colors.white, text="+ Facing"}}
  186.   -- Send and Cancel buttons
  187.   btns[7] = {cmd="send", btn = {x1=2, y1=screenHeight-4, x2=math.floor(screenWidth/2)-1, y2=screenHeight-2, bgColor=colors.lime, textColor=colors.white, text="Send Config"}}
  188.   btns[8] = {cmd="cancel", btn = {x1=math.floor(screenWidth/2)+1, y1=screenHeight-4, x2=screenWidth-2, y2=screenHeight-2, bgColor=colors.gray, textColor=colors.white, text="Cancel"}}
  189.  
  190.   -- Draw all buttons
  191.   for i = 1, #btns do
  192.     drawButton(btns[i].btn)
  193.   end
  194.  
  195.   while true do
  196.     local event, button, x, y = os.pullEvent("mouse_click")
  197.     for i = 1, #btns do
  198.       if inButton(x, y, btns[i].btn) then
  199.         local cmd = btns[i].cmd
  200.         if cmd == "wdec" then
  201.           if configWidth > 1 then configWidth = configWidth - 1 end
  202.         elseif cmd == "winc" then
  203.           configWidth = configWidth + 1
  204.         elseif cmd == "hdec" then
  205.           if configHeight > 1 then configHeight = configHeight - 1 end
  206.         elseif cmd == "hinc" then
  207.           configHeight = configHeight + 1
  208.         elseif cmd == "fdec" then
  209.           configFacing = (configFacing - 1) % 4
  210.         elseif cmd == "finc" then
  211.           configFacing = (configFacing + 1) % 4
  212.         elseif cmd == "send" then
  213.           -- Send configuration command to robot
  214.           local configCmd = "config:" .. configWidth .. ":" .. configHeight .. ":" .. configFacing
  215.           rednet.send(robotId, configCmd)
  216.           term.setCursorPos(1,screenHeight-1)
  217.           print("Config sent: " .. configCmd)
  218.           os.sleep(2)
  219.           return
  220.         elseif cmd == "cancel" then
  221.           return
  222.         end
  223.         redrawConfig()
  224.         for j = 1, #btns do drawButton(btns[j].btn) end
  225.       end
  226.     end
  227.   end
  228. end
  229.  
  230. --------------------------------------------------------------------------------
  231. -- Wait for a button press from a set of buttons; returns the command.
  232. --------------------------------------------------------------------------------
  233. local function waitForButtonPress(buttons)
  234.   while true do
  235.     local event, btn, x, y = os.pullEvent("mouse_click")
  236.     for _, data in ipairs(buttons) do
  237.       if inButton(x, y, data.btn) then
  238.         return data.cmd, data.id
  239.       end
  240.     end
  241.   end
  242. end
  243.  
  244. --------------------------------------------------------------------------------
  245. -- Main UI Loop
  246. --------------------------------------------------------------------------------
  247. local function main()
  248.   while true do
  249.     local mainButtons = drawMainList()
  250.     local event, btn, x, y = os.pullEvent("mouse_click")
  251.     for _, data in ipairs(mainButtons) do
  252.       if inButton(x, y, data.btn) then
  253.         local robotId = data.id
  254.         local submenuButtons = drawRobotMenu(robotId)
  255.         while true do
  256.           local cmd, _ = waitForButtonPress(submenuButtons)
  257.           if cmd == "back" then
  258.             break
  259.           elseif cmd == "stats" then
  260.             rednet.send(robotId, "stats")
  261.             term.setCursorPos(2, term.getSize()-5)
  262.             term.setBackgroundColor(colors.black)
  263.             term.setTextColor(colors.white)
  264.             write("Waiting for stats...")
  265.             local sender, reply, protocol = rednet.receive(nil, 3)
  266.             term.clearLine()
  267.             if sender == robotId and reply then
  268.               write("Stats: " .. reply)
  269.             else
  270.               write("No stats received from robot " .. robotId)
  271.             end
  272.             write(" -- Touch to continue.")
  273.             os.pullEvent("mouse_click")
  274.             submenuButtons = drawRobotMenu(robotId)
  275.           elseif cmd == "config" then
  276.             configureRobot(robotId)
  277.             submenuButtons = drawRobotMenu(robotId)
  278.           else
  279.             rednet.send(robotId, cmd)
  280.             term.setCursorPos(2, term.getSize()-5)
  281.             term.setBackgroundColor(colors.black)
  282.             term.setTextColor(colors.white)
  283.             write("Sent command '" .. cmd .. "' to robot " .. robotId)
  284.             os.sleep(1)
  285.             submenuButtons = drawRobotMenu(robotId)
  286.           end
  287.         end
  288.         break
  289.       end
  290.     end
  291.   end
  292. end
  293.  
  294. --------------------------------------------------------------------------------
  295. -- MAIN: Run the UI and rednet listener in parallel.
  296. --------------------------------------------------------------------------------
  297. parallel.waitForAny(main, handleRednetMessages)
  298.  
  299. if rednet.isOpen(modemSide) then
  300.   rednet.close(modemSide)
  301. end
  302.  
Add Comment
Please, Sign In to add comment