9 posts
Posted 02 February 2013 - 03:28 PM
Title: [Lua][Question]
Hi, I'm trying to make a "turtle security system", however I'm having some difficulty with a program.
On the console I have this:
rednet.open("left")
while true do
rednet.broadcast(read())
end
On the turtle end I have this:
rednet.open("right")
while true do
id, msg == rednet.receive()
if msg == "off" then
turtle.up()
turtle.up()
turtle.up()
end
if msg == "attack" then
turtle.down()
turtle.down()
turtle.down()
while turtle.detectDown ~= true do
turtle.attack()
end
end
end
Basically what it does is, I type "attack" into the console, and the turtle drops down and wails the sword, or I type "off" and the turtle goes back up into it's hiding place. I have only been able to either make it go up, or make it go down and attack, but i haven't been able to make it switch between, given the command. I can only assume that there is some botched code that I'm using, I'm fairly new to this so it wouldn't surprise me. Any suggestions?
497 posts
Location
The Big Apple, NY
Posted 02 February 2013 - 03:39 PM
what do you mean switch between?
also u are missing a end in the turtle script to close the while loop
9 posts
Posted 02 February 2013 - 03:42 PM
Sorry, it is there, I had to copy it from hand. In the console, when I type "attack" it goes down and attacks, by "switching", I want to be able to type "off" and make it stop attacking and go up.
497 posts
Location
The Big Apple, NY
Posted 02 February 2013 - 03:48 PM
well you could spawn a rednet listener coroutine and once the corouine gets a off the other main part of the code stops…
9 posts
Posted 02 February 2013 - 03:51 PM
Could you give/refer a structure for that, I have only been doing this for a few days now, so my understanding of what you just suggested is limited.
497 posts
Location
The Big Apple, NY
Posted 02 February 2013 - 03:53 PM
Honestly i am ok with some parts of CC but one part of CC i am fuzzy with is co routines and i think that my "helping" might do more harm then good :P/>
68 posts
Posted 02 February 2013 - 03:55 PM
You need to attack AND listen to incoming instructions at the same time. You probably don't even need multithreading.
You can do that by just adding these few lines to your existing code:
rednet.open("right")
while true do
id, msg == rednet.receive()
if msg == "off" then
turtle.up()
turtle.up()
turtle.up()
end
if msg == "attack" then
turtle.down()
turtle.down()
turtle.down()
while turtle.detectDown ~= true do
turtle.attack()
local id, msg = os.pullEvent("rednet_message") --this will pull a rednet message event
if msg=="off" then --if it's an instruction to turn off, exit the attack loop
break()
end
end
end
end
(note: this is untested, but if it doesn't work, it's something along these lines)
497 posts
Location
The Big Apple, NY
Posted 02 February 2013 - 03:58 PM
You need to attack AND listen to incoming instructions at the same time. You probably don't even need multithreading.
You can do that by just adding these few lines to your existing code:
rednet.open("right")
while true do
id, msg == rednet.receive()
if msg == "off" then
turtle.up()
turtle.up()
turtle.up()
end
if msg == "attack" then
turtle.down()
turtle.down()
turtle.down()
while turtle.detectDown ~= true do
turtle.attack()
local id, msg = os.pullEvent("rednet_message") --this will pull a rednet message event
if msg=="off" then --if it's an instruction to turn off, exit the attack loop
break()
end
end
end
end
(note: this is untested, but if it doesn't work, it's something along these lines)
just smacking a rednet event in the middle of the code wont solve anything :blink:/>
the program will wait until it gets the rednet message to do anything and unless he tells it to stop it wont ever get a rednet message…
15 posts
Location
Pennsylvania, USA
Posted 02 February 2013 - 04:03 PM
If you've never used coroutines before, the easiest thing to do will be to use the
Parallel (API) which provides a very simple interface.
Basically, you want to split your code into two functions – one that keeps trying to attack, and one that listens to rednet for commands. If you use
parallel.waitForAny, both functions will run in parallel*, so you can have rednet.receive() running (which blocks until a message is received) without holding up your attack loop. There's a short example on the parallel.waitForAny page.
* They don't technically run in parallel – only one coroutine is actually executing at any given time, but from a distance it looks like they're both running at the same time.
9 posts
Posted 02 February 2013 - 04:09 PM
Do you think a "Repeat/Until" loop would be able to work?
repeat
turtle.attack()
until msg == "off"
Or something?
Edit: Will try Raineth
15 posts
Location
Pennsylvania, USA
Posted 02 February 2013 - 04:15 PM
You need to attack AND listen to incoming instructions at the same time. You probably don't even need multithreading.
You can do that by just adding these few lines to your existing code:
rednet.open("right")
while true do
id, msg == rednet.receive()
if msg == "off" then
turtle.up()
turtle.up()
turtle.up()
end
if msg == "attack" then
turtle.down()
turtle.down()
turtle.down()
while turtle.detectDown ~= true do
turtle.attack()
local id, msg = os.pullEvent("rednet_message") --this will pull a rednet message event
if msg=="off" then --if it's an instruction to turn off, exit the attack loop
break()
end
end
end
end
(note: this is untested, but if it doesn't work, it's something along these lines)
You're right, you could also architect your code this way – but it's a little more work than this because os.pullEvent("rednet_message") will block code execution until a message is received. What you would need to do instead is listen for any event (because you can't listen for more than 1 specific type), filter out the ones you don't care about, and use timers to ensure that there are a steady stream of events (otherwise, your turtle will just sit around waiting when nothing is going on.)
For example:
local timer_id = os.startTimer(0.1) -- wake up in at most 100ms
[... inside your main loop ...]
local type, p1, p2 = os.pullEvent()
if type == "rednet_message" then
[handle your message here]
elseif type == "timer" and p1 == timer_id then
timer_id = os.startTimer(0.1) -- start a new timer
end
-- attack any time we receieve an event, whether or not it's one we cared about
turtle.attack()
edit: I forgot that the sender ID is the first value for rednet_message, fixed example.
9 posts
Posted 02 February 2013 - 04:59 PM
Looking over the parallel api, I wasn't able to discern where in the code I should place it, I currently have this:
if msg == "attack" then
while turtle.detectDown ~= true do
paralell.waitForAny(rednet.receive,turtle.attack)
end
if msg == "off" then
turtle.up()
end
Which still manages to punch the crap out of me as I test, but I can't seem to get it to stop with a command.
15 posts
Location
Pennsylvania, USA
Posted 02 February 2013 - 05:18 PM
Looking over the parallel api, I wasn't able to discern where in the code I should place it, I currently have this:
if msg == "attack" then
while turtle.detectDown ~= true do
paralell.waitForAny(rednet.receive,turtle.attack)
end
if msg == "off" then
turtle.up()
end
Which still manages to punch the crap out of me as I test, but I can't seem to get it to stop with a command.
In your code, you're calling rednet.receive() but throwing the result away. You're also never doing anything that would break you out of the loop when you receive a message, so the msg == "off" line will never be run. Finally, in your while loop you forgot the parenthesis after turtle.detectDown (you meant turtle.detectDown()), so you're comparing the function itself (rather than its return value) to true – which it never will be.
I hacked up your original code a bit to give you a better example. I haven't tested it, but this should be pretty close to what you're after:
if not rednet.open("right") then
error("couldn't open rednet!")
end
local attacking = false
function handleMessages()
while true do
local id, msg == rednet.receive()
if msg == "off" then
turtle.up()
turtle.up()
turtle.up()
attacking = false
elseif msg == "attack" then
turtle.down()
turtle.down()
turtle.down()
attacking = true
elseif msg == "terminate" then
return -- parallel.waitForAny() will exit when we return
end
end
end
function attackLoop()
while true do
if attacking then
turtle.attack()
else
os.sleep(1)
end
end
end
-- run until either handleMessages() or attackLoop() returns
parallel.waitForAny(handleMessages, attackLoop)
9 posts
Posted 03 February 2013 - 06:17 AM
Works great, thanks a bunch.