Asked — Edited

Script Control - Looping Functionality Question. A Bug Or Brain Fart?

Situation: I've looked over all the scripts in the cloud and haven't seemed to find anything pertaining to looping. So I wanted to write a short tutorial for the community. So the simple loop example went okay, but as I wrote a loop within a loop. I am finding myself a little confused as the the process flow of the following code...

Here is the script:


#Loop With In Loop
Print("Loop with a loop")
$OuterCounter = 3
$InnerCounter = 2

:OuterLoopStep
  If ($OuterCounter >= 0)
    #Execute Outer Loop Command
    Print(">Outer Loop Value: $OuterCounter)
    $OuterCounter = $OuterCounter - 1

    :InnerLoopStep
      If ($InnerCounter >= 0)
        #Execute Inner Loop Command
        Print("Inner Loop Value: $InnerCounter")
        $InnerCounter = $InnerCounter - 1
        Goto (InnerLoopStep)
      Else 
        Sleep(3000)
        Goto(OuterLoopStep)
        #Wanted to use EndIf for formality, but not nessecary
  Else
    Print("Finished")
  EndIf

Here is the output of the debugger: Start 2: Print("Loop with a loop") Loop with a loop 3: $OuterCounter = 3 4: $InnerCounter = 2 6: :OuterLoopStep 7: If ($OuterCounter >= 0) 9: Print(">Outer Loop Value: $OuterCounter)

Outer Loop Value: 3 10: $OuterCounter = $OuterCounter - 1 12: :InnerLoopStep 13: If ($InnerCounter >= 0) 15: Print("Inner Loop Value: $InnerCounter") Inner Loop Value: 2 16: $InnerCounter = $InnerCounter - 1 17: Goto (InnerLoopStep) 13: If ($InnerCounter >= 0) 15: Print("Inner Loop Value: $InnerCounter") Inner Loop Value: 1 16: $InnerCounter = $InnerCounter - 1 17: Goto (InnerLoopStep) 13: If ($InnerCounter >= 0) 15: Print("Inner Loop Value: $InnerCounter") Inner Loop Value: 0 16: $InnerCounter = $InnerCounter - 1 17: Goto (InnerLoopStep) 13: If ($InnerCounter >= 0) 18: Else 19: Sleep(3000) 20: Goto(OuterLoopStep) 7: If ($OuterCounter >= 0) 9: Print(">Outer Loop Value: $OuterCounter) Outer Loop Value: 2 10: $OuterCounter = $OuterCounter - 1 12: :InnerLoopStep 13: If ($InnerCounter >= 0) 18: Else 19: Sleep(3000) 20: Goto(OuterLoopStep) 7: If ($OuterCounter >= 0) 9: Print(">Outer Loop Value: $OuterCounter) Outer Loop Value: 1 10: $OuterCounter = $OuterCounter - 1 12: :InnerLoopStep 13: If ($InnerCounter >= 0) 18: Else 19: Sleep(3000) 20: Goto(OuterLoopStep) 7: If ($OuterCounter >= 0) 9: Print(">Outer Loop Value: $OuterCounter) >Outer Loop Value: 0 10: $OuterCounter = $OuterCounter - 1 12: :InnerLoopStep 13: If ($InnerCounter >= 0) 18: Else 19: Sleep(3000) 20: Goto(OuterLoopStep) Here's where my confusion starts. Any ideas? Am I missing something obvious? 7: If ($OuterCounter >= 0) 10: $OuterCounter = $OuterCounter - 1 12: :InnerLoopStep 13: If ($InnerCounter >= 0) 18: Else 19: Sleep(3000) 20: Goto(OuterLoopStep) 7: If ($OuterCounter >= 0) 10: $OuterCounter = $OuterCounter - 1 12: :InnerLoopStep 13: If ($InnerCounter >= 0) 18: Else 19: Sleep(3000) 20: Goto(OuterLoopStep) 7: If ($OuterCounter >= 0) 10: $OuterCounter = $OuterCounter - 1 12: :InnerLoopStep 13: If ($InnerCounter >= 0) 18: Else 19: Sleep(3000) 20: Goto(OuterLoopStep)

and on and on the loop executes...


ARC Pro

Upgrade to ARC Pro

Take control of your robot's destiny by subscribing to Synthiam ARC Pro, and watch it evolve into a versatile and responsive machine.

#1  

I'll be watching this thread. I'm on the learning curve of script writing and need all the info I can get. This stuff is very important I think and needed. Hopefully there will an area that's easily referenced in the new Wiki pages talked about in other threads for this kind of stuff.

Good luck!

#2  

Honestly, I'm having some issues with more complex scripts. Problem is, I'm not a programmer, but the results are clearly...weird.

I had the scipt working nearly 100%, but then it seemed to "degrade". I know that's not really possible, it's just code, but I'm getting stumped and confused.

I have a script that attempts to solve getting "boxed in". It checks to the left, it checks to the right, it back out, and then checks again.

It's not clean (lord knows I have no idea what clean code even looks like:) ), but it DID work.

So by degrade, I mean, the simple turn left loop was working just fine for example, now he just spins around and doesn't pass (or fail) any of the conditions like he did before. Nothing material has changed in the code. So what's with that!?!?!

I'll upload the code in a few minutes after I finish banging my head a bit more.

#3  

@Cyberdude

Feel free to send it my way. I'll take a look at it, maybe a different set of eyes can provide some insight.

As far as the scripting unpredictability, well ARC is still and work in progress and any concretely described bugs or quirks can only help DJ as he won't have to spend extra time replicating the error...

#4  

Here ya go. The logic works now, but when it does the final call to the backup routine, it seems to fail (Look at the console dump. Seems to call the routine and execute the first couple lines. However, in practice, I never see anything happen. It stops, but thats it.)...

$pingdist = 0
$pingmax = 20
$timer = 0
$maxtimer = 20

Goto(CheckpingLeft)

:BackUp
  Stop()
  Sleep(1000)
  Left(1000)
  Sleep(1000)
  Reverse(2, 1500) 
  Sleep(1500)
    Halt()          

:CheckpingLeft
  Left(2)
  $pingdist = Getping(d10, d11)
    if($pingdist >= $pingmax)
      Say("Ping greater than $pingdist left")
      Stop()
      Halt()
    Else
      $timer = $timer + 1
         If($timer = $maxtimer)
            Stop()
            $timer = 0
            Sleep(500)
            Goto(CheckpingRight)
          Else
            Goto(checkpingLeft)

:CheckpingRight
  Right(2)
  $pingdist = Getping(d10, d11)
    if($pingdist >= $pingmax)
      Say("Ping greater than $pingdist Right")
      Stop()
      Halt()
        Else
          If($timer = ($maxtimer+20))
          Goto(BackUp)
     $timer = $timer + 1
     Goto(checkpingRight)

And here is the console:Console.zip

#5  

OK, fooled around with my backup routine. I was missing a number in my "left" call ; )

Now the script works. Yay.

PRO
Synthiam
#6  

Ah, I see something. It's a little quirk in the stack. Ooops! I'll fix that this weekend :)

It's when the IF is called within the IF... A little logic error in my compiler .

EZ-Script is not actually a script, even though it has that in the name. The code is compiled into OP Codes and handed off to an interpreter. The interpreter has a hook within the ARC host to control stuff with ControlCommand(), and a reference to the EZ_B.DLL for stuff like Servo, GetPing, etc..

That is why EZ-Script is actually very fast

So the compiler parses your human readable code and converts it to an array of commands, which contain OP Codes and parameters - much like you'd see in Assembly (which I spend a lot of time in for the firmware, so I like it). We call the array of commands the "Program Memory"

The compiler assigns "goto" and "failedCondition" to each command pointing to a location within the "Program Memory". So each Command executes its appropriate OPCode and uses the respective parameters. The goto or failed condition memory location is set as the next program memory location to move to.

Within the interpreter, there are a few ways to move through program memory. Every command has a Goto parameter, which specifies the next memory location to move to. This is usually the next memory location, unless the user code explicitly specifies to GOTO() somewhere :)... That is determined during compiling - and Goto() has no bugs.

The "failedCondition" is where the bug is. If the "if" condition fails, the compiler has a bug when determining the stack and goes to the wrong line number :)

PRO
Synthiam
#7  

As for the speed that I claim, I should show you this :)

This is a test with 1 stack and simple math.


$x=0

:start

  $x = $x + 1

  goto(loop1)

  goto(start)

:loop1

  return()

$x will equal 36,563 in 1.01 seconds

If you think of it in execution steps, that's 4 * 36,563 = 146,252 operations per second on my computer.

User-inserted image

The reason I count 4 steps, is because there are really only 4 operations in the counting part of that code.. The only operations are bolded


$x=0

:start

  $x = $x + 1

  goto(loop1)

  goto(start)

:loop1

  return()

You can see only the operations when you run in the Config Debug view...

Quote:

Start 1: $x=0 3: :start 5: $x = $x + 1 <--- 1 7: goto(loop1) <--- 2 13: return() <--- 3 9: goto(start) <--- 4 5: $x = $x + 1 <--- 1 7: goto(loop1) <--- 2 13: return() <--- 3 9: goto(start) <--- 4 5: $x = $x + 1 7: goto(loop1) 13: return() 9: goto(start) 5: $x = $x + 1 7: goto(loop1) 13: return() 9: goto(start) 5: $x = $x + 1 7: goto(loop1) 13: return() 9: goto(start) 5: $x = $x + 1 7: goto(loop1) 13: return() 9: goto(start)

Because this is an actual "compiled" programming language, it's that fast :)

#8  

:CheckpingRight
Print("Checking right...")
  Print("Right(2)")
  $pingdist = Getping(d10, d11)
    if($pingdist >= $pingmax)
      Say("Ping greater than $pingdist Right")
      Print("Stop()")
      Print("Halt()")
    Else
      If($timer = ($maxtimer+20))
        Print("timer = maxtimer + 20")
        Goto(BackUp)
        Print("Does the following code get executed?")
        $timer = $timer + 1
        Goto(checkpingRight)

I think it might be possible the code formatting may be confusing you...

#9  

@DJ Sures

I thought I smelled smoke on the nested if, but just hadn't done the testing to make the case to you... Man your quick.

PRO
Synthiam
#10  

@LeversofPower:) Thanks dude. It's a great test. When I did the If/ElseIf/Else/Endif a few weeks ago, I thought of that logic condition - but I didn't review it enough. I love how close we are as a community:) The progress EZ-Robot has made in a year gives me the hugest smile. Love it!

Can't wait to see your android app working too. That's such a good idea.

This next release of ARC that i'm working on today has significant improvements for the http url parser, windows 8 tcp server bug fix, and a few other goodies like this...

This kind of works for you right now, $x = 2 > 1 This doesn't work but will work in next release, $x = 2 = 2

And a few fixes like this thread topic logic bug:) .. sometimes I should sleep when i'm tired, instead of programming haha

#11  

WOW DJ is like 146,252 operations per second in his brain!:) and thanks to leversofpower for "if ing" the envelope! :)

#12  

Interesting insight into EZ-Script, I know ;), but it seems that name has stuck. I was really hoping when looking at the product I wouldn't have to get into typing hundreds of curly braces and semicolons to soon.

Thanks for the tip on the debug checkbox. At a cursory glance I didn't pick up on just the operations.

Of course when you feel like it, or on the todo list, or whatever the flow is: Is a pause button in the config window next to the run button is asking to much, otherwise I got a feeling I'm going to be doing a lot of sleeping.

Oh, and a scroll bar on the script control output window...

PRO
Synthiam
#13  

Interesting request for a pause button. You'd like to manually start, stop and pause the script?

Can you give me a rundown on the program you'd like to see this functionality for?

#14  

You guys make my head hurt. This thread really shows me how far out of this stuff I really am. ;) Thanks God for the "EZ" part.

#15  

@leversofpower, Yeah, formatting. Never having taken a single day of programming in my life, I usually just trip and fall my way through this stuff.

Took me three sessions to get this "code" (not script, hehe) working. And since I'm on the bleeding edge of understanding it all, debugging takes on a whole new sense of shock and awe :P

@DJ, Pause (Global, in the case of running from the script control interface) would be nice. I just found myself in a nasty endless-loop-of-doom(tm) whereby no matter how much I pounded on the stop button on the main script, it just ran away because I'm nesting my script command calls.

Had to literally pull the plug and shut down the app to get back to "normal".

Wall-E started compacting the cat and drinking all the GOOD scotch!

#16  

Hmmm, aside from it being useful when testing loops. Not sure I have a specific program in mind at this time. I would say a pause button would not be even be a medium priority enhancement but just nice to have. It seems only useful on scripts of over hundred lines and that run a series of steps rapidly that display a lot in the debug window.

I've only been messing with ARC a couple of days. So it went like this: Camera control, sweet. HTTP server even better. Then, since I'm a programmer by hobby and trade, I immediately went to the script window and started typing. And that's where I've been and where I'll be until the RoboQuad remote is hacked or until the hardware from China arrives in my mail box.

@dschulpius We must all start from somewhere. I was planning a looping tutorial to help out the community. If you have any scripting questions or ideas let me know. I do not know anything about electronics let alone integrating with EZ-B, but my starting point is some cheap stepper motors from china:

Stepper

and this comes next on my plan: Shift Register

used with this Robot Eye

To make this replacement head for RoboQuad:

User-inserted image

Big plans I know, we'll see I guess...

#17  

Wow, that will be better then a lazier light show at a Pink Floyd concert!

PRO
Synthiam
#18  

Compiler's condition tree fixed - sorry for the delay :)


# Loop With In Loop
Print("Loop with a loop")
$OuterCounter = 3
$InnerCounter = 2

:OuterLoopStep

IF ($OuterCounter >= 0)
  
  Print("Outer Loop Value: $OuterCounter)
  $OuterCounter--
  
  :InnerLoopStep
  
  IF ($InnerCounter >= 0)
    Print("Inner Loop Value: $InnerCounter")
    $InnerCounter--
    Goto (InnerLoopStep)
  ELSE 
    Sleep(1000)
    Goto(OuterLoopStep)
  ENDIF 
    
ELSE 
  
  Print("Finished")
  
ENDIF 

User-inserted image