This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
grabmyrooster's profile picture

attempt to compare nil with number

Started by grabmyrooster, 18 September 2016 - 06:25 AM
grabmyrooster #1
Posted 18 September 2016 - 08:25 AM
I've been debugging for about 3 hours and this is the only persisting error. I've taken bits and pieces of mining programs people have written (and shared freely, no theft here) to create a turtle that mines a 3x3 tunnel, then waits for GPS coordinates for the next tunnel. I'm getting stuck when it tries to communicate via rednet to the terminal that I would use to send the coordinates. The full code is at the pastebin here: http://pastebin.com/G5W4Pzab

I'm getting this error at line 259, according to the turtle. Any help is much appreciated!
Bomb Bloke #2
Posted 18 September 2016 - 08:57 AM
You've got some "end"s in the wrong positions; I guess you're intending line 259 to be part of your moveY() function, but it's not. This'd be clearer to you if you went through and cleaned up your indentation.
grabmyrooster #3
Posted 18 September 2016 - 09:03 AM
You've got some "end"s in the wrong positions; I guess you're intending line 259 to be part of your moveY() function, but it's not. This'd be clearer to you if you went through and cleaned up your indentation.

I'm going through now cleaning it up, a lot of formatting was lost when copying things over from my test files. Are there specific 'end's causing the issue?
Bomb Bloke #4
Posted 18 September 2016 - 09:16 AM
The first spot that stands out to me is where you start to define the forward() function (line 119) within sendRequest().
Edited on 18 September 2016 - 07:16 AM
grabmyrooster #5
Posted 18 September 2016 - 09:23 AM
I've updated that local function, it seemed clean enough afterwards and produced the same result.

local function sendRequest()
  rednet.open("right") --Open rednet and clear the console
  term.clear()
  term.setCursorPos(1,1)
  local digBlocks = false --Extra parameters: whether to dig blocks or attempt to go over
  local goneUp = 0 --dir and goneUp are used to keep track of position
  local dir = 0
  function forward()
    while not turtle.forward() do --If turtle cannot go forward (either out of fuel or block blocking)
    print("Can't move, checking fuel")
	  if turtle.getFuelLevel() == 0 then
	    checkdig()
	    turtle.select(14) --This selects the ender chest connected to a fuel supply
	    turtle.place() --This places the ender chest
	    turtle.select(1) --This selects slot 1, where fuel would go
	    turtle.suck() --This pulls a stack out of the chest
	    turtle.refuel()
	    turtle.select(14)
	    turtle.dig()
	  end
	  if digBlocks then --If digBlocks var was true the turtle will dig thorugh the blockage otherwise will go over
	    turtle.dig()
	  else
	    turtle.up()
	    goneUp = goneUp + 1
	  end
    end
    while goneUp > 0 and not turtle.detectDown() do --Make sure to compensate for going up and over blocks by going down when next possible
	  turtle.down()
	  goneUp = goneUp - 1
    end
  end
  function up() --Same as forward, for up
    while not turtle.up() do
    print("Can't move, checking fuel")
	  if turtle.getFuelLevel() == 0 then
	    checkdig()
	    turtle.select(14)
	    turtle.place()
	    turtle.select(1)
	    turtle.suck()
	    turtle.refuel()
	    turtle.select(14)
	    turtle.dig()
    end
    if digBlocks then
	  turtle.digUp()
    end
    end
  end
  function down() --Same as forward, for down
    while not turtle.down() do
    print("Can't move, checking fuel")
	  if turtle.getFuelLevel() == 0 then
	    checkdig()
	    turtle.select(14)
	    turtle.place()
	    turtle.select(1)
	    turtle.suck()
	    turtle.refuel()
	    turtle.select(14)
	    turtle.dig()
	  end
	  if digBlocks then
	    turtle.digDown()
	  end
    end
  end
  function getPos() --Gets the position of the turtle from local GPS towers
    print("Getting position")
    cx, cy, cz = gps.locate(10)
    print(cx, cy, cz)
  end
  function getDir() --Gets the heading of the turtle by taking position, moving forward 1 and comparing the 2 positions
    print("Getting direction")
    getPos()
    ox, oy, oz = cx, cy, cz
    forward()
    getPos()
	  if oz > cz then dir = 0
	  elseif oz < cz then dir = 2
	  elseif ox < cx then dir = 1
	  elseif ox > cx then dir = 3 end
	  print(dir)
	  turtle.back()
	  getPos()
  end
  function turn(d) --Turns to heading "d", uses getDir() to calculate how many turns are needed
    getDir()
    print("Aligning")
    print(dir, d)
	  while dir ~= d do
	    turtle.turnRight()
	    dir = dir + 1
	    if dir == 4 then dir = 0 end
	  end
  end
  function moveX() --Combine the past functions to move along the x axis
    print("Moving X")
    getPos()
    if abx > cx then --The current and destination coordinates are compared to decide which heading is needed and distance to move
	  turn(1)
	  for x = 1, abx - cx do
	    forward()
	    cx = cx + 1
	  end
    elseif abx < cx then
	  turn(3)
	  for x = 1, cx - abx do
	    forward()
	    cx = cx - 1
	  end
    end
  end
  function moveZ() --The same as moveX() but for the Z axis
    print("Moving Z")
    getPos()
    if abz > cz then
	  turn(2)
	  for z = 1, abz - cz do
	    forward()
	    cz = cz + 1
	  end
    elseif abz < cz then
	  turn(0)
	  for z = 1, cz - abz do
	    forward()
	    cz = cz - 1
	  end
    end
  end
  function moveY() --The same as moveX() but for the Y axis, as the movement is vertical no turn calcuations are needed so this function is shorter
    print("Moving Y")
    getPos()
    if aby > cy then
	  for z = 1, aby - cy do
	    up()
	    cy = cy + 1
	  end
    elseif aby < cy then
	  for z = 1, cy - aby do
	    down()
	    cy = cy - 1
	  end
    end
  end
  getPos()
  if aby > cy then --If the turtle has to move upwards to get to the destination if moves up first, if it needs to move down if moves down last
    moveY()
    moveX()
    moveZ()
  else
    moveX()
    moveZ()
    moveY()
  end
end
Bomb Bloke #6
Posted 18 September 2016 - 11:29 AM
You're still defining functions within functions, although now it appears intentional. There's no apparent reason to do it here, though - declaring the moveY() / moveX() / etc functions in the global scope every time sendRequest() is called will simply overwrite the old pointers over and over (all blocks within your script share the same global environment table unless you specifically define and assign different ones). If you made them local to sendRequest() instead, you'd still be wasting time redeclaring functions that need only be defined once.

Though it does now appear that aby and cy can be defined before reaching that line. If they're not, then either the third argument passed to the script was not a numeric representation (making aby nil - see line 9), or the system was unable to get a GPS response (making cy nil - see line 182). You can narrow it down by printing the types before 259:

print("aby: " .. type(aby) .. "   cy: " .. type(cy))
grabmyrooster #7
Posted 18 September 2016 - 10:26 PM
I would've thought that lines 7-10 would be giving aby, abx, abz numerical values as tArgs and function getPos() would give cx, cy, cz numerical values as well. Does it have something to do with the beginning lines?


local tArgs={...}
local abx = tonumber(tArgs[2])
local aby = tonumber(tArgs[3])
local abz = tonumber(tArgs[4])

I moved all functions out of local function sendRequest() and made them local functions that are defined on their own, and it gives the same problem so it didn't do anything other than make it cleaner.
grabmyrooster #8
Posted 18 September 2016 - 10:58 PM
I separated the program back into its original 3 programs, and found the underlying problem. The goto function is attempting to call gox, goy, goz (which are abx, aby, and abz but i found/replaced all of them) from the request file. Since the goto program hasn't called the coordinates on its own, it doesn't have them and treats them as nil. All I need to do is combine goto and request in a way that it sends the request and waits for a response, then once a response is received. goes to those coordinates.
grabmyrooster #9
Posted 19 September 2016 - 12:03 AM
I've gotten it to the point where it will send the rednet broadcast requesting coordinates, and will connect to the terminal that is listening for turtles. However it is still throwing the same error in the title. So either gox or cx isn't being properly defined and I can't for the life of me figure out which.

This pastebin is the terminal script: http://pastebin.com/DkdjbFDz

This pastebin is the goto/request hybrid script, throwing an error on line 104 currently: http://pastebin.com/bMf8XZgY
grabmyrooster #10
Posted 19 September 2016 - 02:51 AM
Just in case anyone takes a peek at this and can help: still no dice. I've determined the issue is the gox, goy, goz coordinates (abx, aby, abz). cx, cy, cz all work fine and are successfully called and defined any time getPos() is run. I've found no way to properly define gox, goy, goz since they are acquired from the terminal. So it's either an issue with the terminal coding, the goto coding, or both of them communicating.
Edited on 19 September 2016 - 12:53 AM
Bomb Bloke #11
Posted 19 September 2016 - 10:50 AM
At this point I'm suspecting you've got another system in the area sending out rednet broadcasts. You're not performing any checks to ensure that the messages you're receiving are all coming from the same source.

Because only strings can be send over rednet the coordinates are changed to and from strings on each side of the message

Truth be told, unless you're using a very old build of ComputerCraft (something prior to 1.53), you could simply bundle a whole bunch of values together and send them within a single table. Even with an older build, you could do that by employing textutils.serialise().

I'm not sure how far you'd have to go back before you'd lose the ability to send numbers directly. Rather, I suspect it's always been possible to send those.
grabmyrooster #12
Posted 19 September 2016 - 06:43 PM
I've got no internet on my desktop, so any help I've been getting including this forum I've been doing on my phone. I transfer the files to my phone then copy it all over to pastebin. I am using ComputerCraft version 1.5, because I'm unable to update my whole modpack on just my phone. What's an example of using textutils.serialise() so I can try that after work tonight, if you don't mind?
Bomb Bloke #13
Posted 20 September 2016 - 05:15 AM
Spoiler
rednet.open("right")

local function clear() term.clear() term.setCursorPos(1, 1) end

while true do
	clear()
	print("Connected, ID: ", os.computerID(), ". Listening for turtles")
	local id, msg = rednet.receive() --Wait for a turtle to say it is "Listening"
	
	if msg == "Listening" then
		local toSend = {"goto"}  -- toSend will point to a table, toSend[1] == "goto"
		
		clear()
		
		-- Alarm:
		rs.setOutput("back", true)
		sleep(3)
		rs.setOutput("back", false)
		
		print("Turtle found, enter goto coordinates.")
		
		repeat
			write("Enter X: ")            -- Ask this over and over...
			toSend[2] = tonumber(read())  -- ... because tonumber() returns nil if passed something it can't convert...
		until toSend[2]                       -- ... so we'd best loop until toSend[2] is non-nil.
		
		repeat
			write("Enter Y: ")
			toSend[3] = tonumber(read())
		until toSend[3]        
		
		repeat
			write("Enter Z: ")
			toSend[4] = tonumber(read())
		until toSend[4]   
		
		clear()
		
		print("Coordinates are: ")
		print("X: ",toSend[2])
		print("Y: ",toSend[3])
		print("Z: ",toSend[4])
		print("Sending coordinates...")

		rednet.send(id, textutils.serialize(toSend))  -- Convert table to string representation, and send that.
		
		sleep(2)  -- This merely serves to keep the text on the screen a moment.
	end
end

Spoiler
rednet.open("right") --Open rednet and clear the console

term.clear()
term.setCursorPos(1,1)

-- Variable definitions:

local digBlocks = false --Extra parameters: whether to dig blocks or attempt to go over
local goneUp = 0 --dir and goneUp are used to keep track of position
local dir = 0

local cx, cy, cz, gox, goy, goz

-- Function definitions:

local function checkFuel()
	if turtle.getFuelLevel() < 10 then
		if digBlocks then
			turtle.dig()
		elseif turtle.detect() then
			print("Low on fuel, chest location blocked, will try refuelling later...")
			return
		end
		
		turtle.select(14)
		turtle.place()
		turtle.suck()
		turtle.refuel()
		turtle.dig()
		
		if turtle.getFuelLevel() == 0 then print("Warning: Out of fuel, can't refuel!") end
	end
end

local function forward()
	while not turtle.forward() do --If turtle cannot go forward (either out of fuel or block blocking)
		turtle.attack()
		checkFuel()
		
		if digBlocks then --If digBlocks var was true the turtle will dig thorugh the blockage otherwise will go over
			turtle.dig()
		else
			turtle.up()
			goneUp = goneUp + 1
			cy = cy + 1
		end
	end
	
	while goneUp > 0 and not turtle.detectDown() do --Make sure to compensate for going up and over blocks by going down when next possible
		turtle.down()
		goneUp = goneUp - 1
		cy = cy - 1
	end
	
	if dir == 0 then
		cz = cz - 1
	elseif dir == 1 then
		cx = cx + 1
	elseif dir == 2 then
		cz = cz + 1
	elseif dir == 3 then
		cx = cx - 1
	end
end

local function up() --Same as forward, for up
	while not turtle.up() do
		turtle.attackUp()
		checkFuel()
		
		if digBlocks then
			turtle.digUp()
		else
			print("Warning: I'm obstructed from going up!")
		end
	end
	
	cy = cy + 1
end

local function down() --Same as forward, for down
	while not turtle.down() do
		turtle.attackDown()
		checkFuel()
		
		if digBlocks then
			turtle.digDown()
		else
			print("Warning: I'm obstructed from going down!")
		end
	end
	
	cy = cy - 1
end

local function getPos() --Gets the position of the turtle from local GPS towers
	print("Getting position")
	
	while true do
		cx, cy, cz = gps.locate()
		
		if cx then
			break
		else
			print("Warning: Unable to query GPS!")
			sleep(5)
		end
	end
	
	print("I'm at " .. cx .. "x" .. cy .. "x" .. cz)
end

local function turn(d) --Turns to heading "d"
	print("Aligning")
	print(dir, d)
	
	while dir ~= d do
		turtle.turnRight()
		dir = dir + 1
		if dir == 4 then dir = 0 end
	end
end

local function moveHorizontal() --Combine the past functions to move along the x axis
	print("Moving X")
	
	if gox > cx then --The current and destination coordinates are compared to decide which heading is needed and distance to move
		turn(1)
	elseif gox < cx then
		turn(3)
	end
	
	for x = 1, math.abs(gox - cx) do forward() end

	print("Moving Z")
	
	if goz > cz then
		turn(2)
	elseif goz < cz then
		turn(0)
	end
	
	for z = 1, math.abs(goz - cz) do forward() end
end

local function moveVertical() --The same as moveX() but for the Y axis, as the movement is vertical no turn calcuations are needed so this function is shorter
	print("Moving Y")

	if goy > cy then
		for z = 1, goy - cy do up() end
	elseif goy < cy then
		for z = 1, cy - goy do down() end
	end
end

-- Initialisation:

print("Getting direction")  -- We only need to do this once, no need for a function

getPos()

local ox, oy, oz = cx, cy, cz

while not forward() do turtle.turnRight() end
getPos()

if oz > cz then
	dir = 0
elseif oz < cz then
	dir = 2
elseif ox < cx then
	dir = 1
elseif ox > cx then
	dir = 3
end

print(dir)

-- Main program loop:

while true do
	print("Connected, ID: ", os.computerID(), ". Listening for requests.")
	rednet.broadcast("Listening") --Tell all other computers in the area that this turtle is ready and waiting for orders
	local id, msg = rednet.receive(10) --Wait for a return message for 10 seconds, then repeat
	
	msg = textutils.unserialise(msg)
		
	if type(msg) == "table" then
		if msg[1] == "goto" then
			print("Goto request from ", id, "...")

			gox, goy, goz = msg[2], msg[3], msg[4]

			if goy > cy then --If the turtle has to move upwards to get to the destination if moves up first, if it needs to move down if moves down last
				moveVertical()
				moveHorizontal()
			else
				moveHorizontal()
				moveVertical()
			end
		end
	end
end

Can't say I've tested it, but you should be able to get the general idea.
Edited on 20 September 2016 - 03:17 AM
grabmyrooster #14
Posted 24 September 2016 - 06:22 AM
So in the past few days I've had basically no luck. I'm putting it to rest until I get internet hopefully next week because doing all of this from my phone is a little tedious. For right now since all 8 turtles follow the same pattern, I'm going to set up a script that just has them follow the same set path over and over again, a certain number of times. I'll make a new thread most likely or attempt to figure it out another way. Thanks for all the help!!