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

Lua - Timer events don't seem to be queuing.

Started by Prof_Noobland, 23 February 2013 - 07:16 PM
Prof_Noobland #1
Posted 23 February 2013 - 08:16 PM
Title: Lua - Timer events don't seem to be queuing.

I've been working on a relatively simple program which is meant to control the inputted materials to 4 industrial grinders (feed the beast, but largely irrelevant to this question) via a turtle.

Image of my project, for context:


The gist of it is that there are 4 tubes which my turtle must send items down as quick as it can; however, once a tube has been used, it cant be used again for a certain amount of time. To solve this problem, I thought that I would set 4 timers, each representing the 'cooldown time' of the repective tube, so that i could use os.pullEvent("timer") to get the number of the tube that had come free first.


facing = 1
compareSlot = 16
cellSlotStartSlot = 14
cellSlotCount = 2
numMaterialSlots = 2
cellWireColors = {colors.blue, colors.orange}
materialCells = { 1, 2}
tubeEvents = {}
tubeWaitTime = 5
function orientateSelf()
  turtle.down()
  while turtle.detect() do
	turtle.turnRight()
  end
  turtle.turnLeft()
  turtle.turnLeft()
end
function faceTube(tube)
  if tube > 2 then
	turtle.up()
  else
	turtle.down()
  end

  if tube % 2 == 0 then
	if facing ~= 2 then
	  turtle.turnRight()
	  facing = 2
	end
  else
	if facing ~= 1 then
	  turtle.turnLeft()
	  facing = 1
	end
  end
end
function getNewItems()
  turtle.up()
  turtle.select( compareSlot )
  return turtle.suckUp()
end
function prepareCell( cellInd )

  cellSlot = cellSlotStartSlot - 1 + cellInd;
  turtle.select(cellSlot)

  if turtle.getItemCount(cellSlot) < 1 then
	turtle.down()
	print("retrieving new cells")
  
	if facing ~= 1 then
	  turtle.turnLeft()
	  facing = 1
	end
  
	redstone.setBundledOutput("bottom", cellWireColors[ cellInd] )
	while not redstone.testBundledInput("bottom", cellWireColors[ cellInd]) do
  
	end
	redstone.setBundledOutput("bottom", 0 )
  
	turtle.turnLeft()
  
	while not turtle.suck() do
	
	end
  
	turtle.turnRight()
  end

end
function getItemMaterial()
  turtle.select( compareSlot )
  for i = 1, numMaterialSlots do
	if turtle.compareTo(i) then
	  return i
	end
  end
end
orientateSelf()
table.insert(tubeEvents, os.startTimer( tubeWaitTime ))
table.insert(tubeEvents, os.startTimer( tubeWaitTime ))
table.insert(tubeEvents, os.startTimer( tubeWaitTime ))
table.insert(tubeEvents, os.startTimer( tubeWaitTime ))
while true do
  turtle.select( compareSlot )
  if turtle.getItemCount( compareSlot) > 0 then
	local mat = getItemMaterial()
	prepareCell(materialCells[mat])
  
	local event, param = os.pullEvent("timer")
	for i= 1, 4 do
	  if param == tubeEvents[i] then
		print(i)
		faceTube(i)
	  
		turtle.drop(1)
		turtle.select(compareSlot)
		turtle.drop(1)
	  
		tubeEvents[i] = os.startTimer( tubeWaitTime )
		break
	  end
	end
  
  else
	print("retrieving new items")
	while not getNewItems() do
	
	end
  end
end
Note: please excuse the use of long loops instead of sleep commands - at the time it was a quick fix to the problem of the sleep command removing the events.


That did not go according to plan - only one timer event would fire. I fiddled around a bit, and didn't find much out; only that for some reason giving the tubes different cooldown times would sometimes allow 2 to fire reliably.

I'm really not sure what to make of it - do the events in the queue have some sort of expiry time or does the queue have a very limited length - I don't even think that makes sense.


I've recently changed my program to simply look continuously through the tubes, and it works fine, but I'd really like to know where I was going wrong.


Any help, or really any more detailed information of timers and the way events are handled, would be greatly appreciated.


Thanks in advance,

Prof. Noobland
Lyqyd #2
Posted 24 February 2013 - 04:30 PM
Turtle calls eat events, so your timers are most likely being destroyed when the turtle turns. For instance, if you have two timers fire almost simultaneously, you'd pull the first off the queue, then the turtle would turn, destroying the second timer event.
Prof_Noobland #3
Posted 25 February 2013 - 07:24 PM
Damn. So sleep commands and turtle calls 'eat' events. That's really annoying. Is there any other calls that also have that effect?

So, to be clear, no queued event will be eaten normally by turtle calls, but after pullEvent() is called they (the current queue of events) will be?

Thanks for your help. As before any additional information would be great.
GopherAtl #4
Posted 25 February 2013 - 07:32 PM
Unless I'm forgetting something, only turtle commands, sleep, read, and rednet.receive eat events.

All of these eat events because all of them internally wait for some specific event; sleep waits for a specific timer, read for key/char events, rednet.receive for rednet_message/modem_message events. Less obviously, behind the scenes, turtle commands are actually queued and processed in a separate java thread, so the turtle api wrapper waits for the event sent from that thread back to the main cc thread before returning.

You can call turtle.native.whatever instead of just turtle.whatever. I don't recommend this in general, but since your turtle is only turning and dropping into fixed tubes, never moving or doing anything else that has unpredictable results that affect the next turtle action, it shouldn't be a problem in your case to just change the calls to turtle.native.drop, turtle.native.select, and turtle.native.turnLeft/Right.
immibis #5
Posted 26 February 2013 - 12:56 AM
Damn. So sleep commands and turtle calls 'eat' events. That's really annoying. Is there any other calls that also have that effect?

So, to be clear, no queued event will be eaten normally by turtle calls, but after pullEvent() is called they (the current queue of events) will be?

Thanks for your help. As before any additional information would be great.
Anything that waits will eat events, as it's waiting for its own event internally.

An alternative:
Instead of keeping track of the timer events that will fire when each tube is free, keep track of the time when each tube will be free.
Then you can check each one to see if it's free yet. If no tubes are free, sleep() for the amount of time left until one is.
To get the time use os.clock(), this returns a number that increases by 1 every second. (actually by 0.05 every tick)
Prof_Noobland #6
Posted 27 February 2013 - 03:51 PM
Ah, thanks guys, It all makes sense now. Very helpful indeed.

I think I'll use the clock() function - I'm not sure why I decided against using the time functions in the first place.


Thanks again!