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

Wireless control activator for turtle throwing a "Too Long Without Yielding" error

Started by Chaz, 16 January 2016 - 07:20 PM
Chaz #1
Posted 16 January 2016 - 08:20 PM
Heyo again! More programming troubles abound. This time around I'm trying to make a wireless system that remotely controls a turtle in a mob-grinder area.

The turtle itself (named JCVD, just because I have a penchant for naming my turtles silly things) has a simple startup, it's a while true do loop of turnLeft and attack. It stays in one place and attacks mobs that are led to it.

To keep things simple and safe, I've set JCVD on top of a computer, which has wrapped JCVD as a peripheral. So here's what I've got so far:


modem=peripheral.wrap("bottom")
modem.open(3)
jcvd=peripheral.wrap("top")
jcvd.turnOn()
local event, side, rcv, rpl, msg, dst=os.pullEvent("modem_message")
while true do
  if msg=="jcvdon" then
	jcvd.turnOn()
	modem.transmit(1,3, "JCVD is turned on!")
  elseif msg=="jcvdoff" then
	jcvd.shutdown()
	modem.transmit(1,3, "JCVD is turned off!")
  else
	modem.transmit(1,3, "Didn't catch that. Try again?")
  end
end

After that, it's a relatively simple case of writing a couple of programs on my pocket computer that transmit the respective messages to turn JCVD on and off.

The trouble I'm having, as mentioned in the title, is that it'll receive the first command just fine, but after that it won't receive anything, and will throw a "Too long without yielding" error message. I already see at least one mistake in the code but I thought I'd check in with some pros and figure out how to do what I want to do.
Edited on 16 January 2016 - 07:21 PM
HPWebcamAble #2
Posted 16 January 2016 - 09:14 PM

modem=peripheral.wrap("bottom")
modem.open(3)
jcvd=peripheral.wrap("top")
jcvd.turnOn()

local event, side, rcv, rpl, msg, dst=os.pullEvent("modem_message") --# This will only receive 1 message!

while true do

  --# It should be here instead

  if msg=="jcvdon" then
	jcvd.turnOn()
	modem.transmit(1,3, "JCVD is turned on!")
  elseif msg=="jcvdoff" then
	jcvd.shutdown()
	modem.transmit(1,3, "JCVD is turned off!")
  else
	modem.transmit(1,3, "Didn't catch that. Try again?")
  end

end

I also wanted to mention that this program will reply 'Didn't catch that. Try again?' every time any program trys to communicate on channel 3
It should really just ignore messages that it isn't looking for.
Edited on 16 January 2016 - 08:14 PM
Chaz #3
Posted 16 January 2016 - 10:20 PM
Ah, gotcha! Yeah, looks like I can do without the error message as well, should be fine.

Thanks for the help! I'm working the system a different way now but the principle should be the same, I'll give it a go!
Chaz #4
Posted 16 January 2016 - 10:46 PM
Alright, new issue. I'm now attempting to control the turtle directly through an attached wireless modem Here's my code (I want it to continue turning and attacking until it receives the "jcvdoff" command, at which point it should return to listening for a "jcvdon" command):


modem=peripheral.wrap("left")
modem.open(3)
while true do
  local event, side, snd, rcv, msg, dst = os.pullEvent("modem_message")
  if msg=="jcvdon" then
    while true do
      local event, side, snd, rcv, msg, dst = os.pullEvent("modem_message")
	  if msg=="jcvdoff" then return end
	  turtle.turnLeft()
	  turtle.attack()
    end
end

I thought maybe the issue was that I declared the pullevent twice, but even after removing it and trying that way, the error is the same - It says it expects an "end" at the last line… which is already there. Not sure where I'm going wrong on this part.
Lupus590 #5
Posted 16 January 2016 - 11:12 PM
Have you code set a boolean for keeping track of the jcvd on/off state.

Then look at the boolean for doing stuff


--#inside while true loop, no loop because I'm lazy
--#also this be psudo code
message = pullModemEvent()
if message == on then
  doStuffBool = true
elseif message == off then
  doStuffBool = false
else
  --#other message processing
end


if doStuffBool then
  --#do stuff
end
HPWebcamAble #6
Posted 16 January 2016 - 11:33 PM
snip

Err what? That'll pause for a message, then do stuff, but it can't receive the message while its doing stuff.

It says it expects an "end" at the last line… which is already there. Not sure where I'm going wrong on this part.

You are actually missing an 'end', to close the if statement on line 5


If I was designing this program, I'd just have the turtle always be on. It's not using fuel or anything.
If I had to turn it off, I'd use redstone, like this:

while true do
  if rs.getInput("bottom") then
    turtle.turnLeft()
    turtle.attack()
  else
    sleep(2)
  end
end
Bomb Bloke #7
Posted 16 January 2016 - 11:34 PM

modem=peripheral.wrap("left")
modem.open(3)
while true do    --# Open block 1
  local event, side, snd, rcv, msg, dst = os.pullEvent("modem_message")
  if msg=="jcvdon" then    --# Open block 2
    while true do    --# Open block 3
      local event, side, snd, rcv, msg, dst = os.pullEvent("modem_message")
	  if msg=="jcvdoff" then return end    --# Open block 4
	  turtle.turnLeft()
	  turtle.attack()
    end    --# End block 4
end    --# End block 3
--# Block 2 still open?
--# Block 1 still open?

Proper indentation makes it easier to avoid this sort of problem.
Chaz #8
Posted 16 January 2016 - 11:47 PM
Okay, I got it to stop throwing errors, but yeah, once it gets to that second pullEvent the system won't perform any other commands. I'm not quite sure how to work around this, I want the system to keep reading for inputs any time I want to start or stop the command wirelessly, but it's proving to be kind of tricky.
HPWebcamAble #9
Posted 16 January 2016 - 11:54 PM
Okay, I got it to stop throwing errors, but yeah, once it gets to that second pullEvent the system won't perform any other commands. I'm not quite sure how to work around this, I want the system to keep reading for inputs any time I want to start or stop the command wireless, but it's proving to be kind of tricky.

Assuming you still really want to use modems as opposed to redstone, you might be able to do this:
(Haven't tested it)

local state = true

local function attack()
  while true do
	if state then
	  turtle.attack()
	  turtle.turnLeft()
	else
	  sleep(2)
	end
  end
end

local function messages()
  while true do
	local event, side, snd, rcv, msg, dst = os.pullEvent("modem_message")
	if msg == "on" then
	  state = true
	elseif msg == "off" then
	  state = false
	end
  end
end

parallel.waitForAny( attack , messages )
Edited on 16 January 2016 - 10:54 PM
Dragon53535 #10
Posted 16 January 2016 - 11:54 PM

--#inside while true loop, no loop because I'm lazy
--#also this be psudo code
message = pullModemEvent()
if message == on then
  doStuffBool = true
elseif message == off then
  doStuffBool = false
else
  --#other message processing
end


if doStuffBool then
  --#do stuff
end

Rewritten to work:


local doStuffBool = false
local timer = os.startTimer(1) --# This will make the turtle attack once every second if it's told to attack. You can change this down, try to make it not too fast.
while true do
local event, side, snd, rcv, msg, dst = os.pullEvent()--#Notice lack of "modem_message"
  if event == "modem_message" then
   if msg == "on" then
     doStuffBool = true
   elseif msg == "off" then
     doStuffBool = false
   else
	  --#other message processing
   end
  end
  if event == "timer" then
	if doStuffBool then
	  turtle.turnLeft()
	  turtle.attack()
	end
	timer = os.startTimer(1) --#What you change up there, you should change down here.
  end
end
Edited on 16 January 2016 - 11:05 PM
HPWebcamAble #11
Posted 17 January 2016 - 12:06 AM
Rewritten to work:

Assuming Chaz wants the turtle to constantly turn in circles attacking until it receives a message, that won't work, like I said.
Dragon53535 #12
Posted 17 January 2016 - 12:14 AM
Alright, new issue. I'm now attempting to control the turtle directly through an attached wireless modem Here's my code (I want it to continue turning and attacking until it receives the "jcvdoff" command, at which point it should return to listening for a "jcvdon" command):
–snip–

Edit: It occurs to me that you might of written that while I was editing it to actually work correctly.

Edit2: And also, I ENTIRELY misread what you typed :P/> I thought for whatever reason you said that he said that he didn't want it to do so.
Edited on 16 January 2016 - 11:20 PM
Bomb Bloke #13
Posted 17 January 2016 - 12:25 AM
Assuming you still really want to use modems as opposed to redstone, you might be able to do this:
(Haven't tested it)
...
	  sleep(2)
...

This line here could be replaced with just "os.pullEvent("modem_message")" to help prevent unneeded looping. You'd also want to wrap the modem and open the channel, but I assume you can see that for yourself, Chaz.
Chaz #14
Posted 17 January 2016 - 12:28 AM
Honestly, it sounds like HPWebcamAble's redstone-based method does the trick a lot more simply than the one I was using. I think I've been able to figure it out now, this method still uses wireless modems, but it uses the computer's ability to emit a redstone signal as well.

I put HPWebcamAble's redstone-based program into JCVD as his startup, and placed a computer below him (Which is serving as the "JCVDock"). The dock is set so that when it's turned on, it boots up JCVD (As I needed a way to safely switch him on without being in the murder room he's based in), and when it receives a jcvdon signal it turns on a redstone signal on its top, when it receives a jcvdoff command it turns it off again. This should do the trick.

Apologies, I sort of went looking for a more complex solution when the simpler ones do the trick, haha.
Edited on 16 January 2016 - 11:29 PM
HPWebcamAble #15
Posted 17 January 2016 - 01:04 AM
Apologies, I sort of went looking for a more complex solution when the simpler ones do the trick, haha.

Trust me, you aren't the first ;)/>