rollo-npm
The Rollo programming language for the Orbotix Sphero robot using Node.js and Cylon.js
Rollo is still early code!
I'm still building out and designing Rollo. Things are being added often, though generally in a backwards compatible way.
Quick start
Add the Rollo dependency to your project with this:
npm install rollo
Or this, if you want it saved to your package.json
file:
npm install rollo --save
In order to make use of Rollo, you need to require it in your source code where it is accessible from your main Cylon.js work function:
var Rollo = require('rollo');
To run a Rollo script/program, you need to pass Rollo's run function a reference to your Sphero (typically by using the my
parameter Cylon,js sends to your work
function), a string that contains your Rollo program's source code, and a callback. The callback will be executed when all of the Rollo commands have been run by your Sphero:
var source = "go 2\n right\n go 2";
Rollo.run(my.sphero, source, function() {
console.log("ROLLO: Shutting down");
});
If you prefer, you can pass a string with a full or relative file path to the source file by calling runFile()
instead of the previous example's run()
:
Rollo.runFile(my.sphero, "~/myScript.rol", function() {
console.log("ROLLO: Shutting down");
});
Table Of Contents
Check out the example program
You can check out the example program here if you want to get up and running with something basic.
Sample Rollo script
The following Rollo program will cause the Sphero to make a 'C' shape, reverse direction, and retrace its steps.
# setup the starting color, flash green, and then wait
color 'darkgray'
flash 'green'
waitForTap 3 seconds
# set speed and go!
speed 25
go 2
repeat 2 times { # call the rightAndGo sub twice
gosub rightAndGo
}
# do a 180 degree turn and go again
reverse
go 2
repeat 2 times { # run the leftAndGo sub two times
gosub leftAndGo
}
# this is a subroutine that gets called from other parts of the code
sub rightAndGo {
right
go 2
}
# this is another subroutine
sub leftAndGo {
left
go 2
}
Configuring Rollo
Currently Rollo allows for only a few configuration options. You access them through the Rollo object that you require
into your application.
setDebug()
You can configure debug mode, which outputs every Rollo line executed to the Node.js console log, by passing a true or false value to the setDebug()
function, as shown in the following example:
var Rollo = require('rollo');
Rollo.setDebug(true); // false is the default
setEcho()
You can configure whether or not the output of Rollo say
commands will be output to the Node.js consolel log by passing a true or false value to the setEcho()
function, as shown in the following example:
var Rollo = require('rollo');
Rollo.setEcho(true); // false is the default
Capturing Rollo Events
registerLineEvent()
Your application can be notified through a callback whenever a new line is being run by the Rollo exec process. This would be useful if, say, you wanted to highlight each line in your code as it is run through some sort of user interface you've built. You do this by calling the registerLineEvent()
method on the Rollo object and pass it a callback. Your callback will be called with a single data parameter that contains the parsed line object.
That object has two properties, number
and line
. Number is the line number of the currently running line in the source you passed to Rollo. The line property in the object contains the command and any parameters.
var Rollo = require('rollo');
Rollo.registerLineEvent(function(data) {
console.log("LINE: " + data.number);
});
registerSayEvent()
Your app can receive the output of any executed say
commands by using the registerSayEvent()
method and passing it a callback. Your callback will receive one parameter, which is the text that was sent as a parameter to the say
command. You use it like in the following:
var Rollo = require('rollo');
Rollo.registerSayEvent(function(text) {
console.log("Rolo said: " + text);
});
registerLogEvent()
Your app can receive the output of any console logging output by the Rollo command processor by using the registerLogEvent()
method and passing it a callback. Your callback will receive one parameter, which is the text that was logged to the console. You use it like in the following:
var Rollo = require('rollo');
Rollo.registerLogEvent(function(text) {
console.log("Rolo log: " + text);
});
Stopping a Running Program
Your app can stop a Rollo program that is in progress by issuing the stop()
command on the main Rollo object:
var Rollo = require('rollo');
Rollo.stop();
Rollo Syntax
Rollo is a simple language that is intended for kids and non-programmers. Commands are meant to be simple to understand and offer flexible syntax. The main structure is the command followed by 0 or more parameters. For example:
right
This causes the Sphero to turn right.
Rollo allows people to put notes inside of their programs to make it easier for other people, or the programmer him or herself, to figure out what's going on. These are called comments.
You can put comments on their own line, or you can add them to the end of a line that contains Rollo commands. They can make your code a lot more readable.
# This is a comment
go 2 seconds # this line will make the Sphero go straight for 2 seconds
# The next line will change the color of the Sphero to orange
color 'orange'
Case Insensitive
Apart from things inside quotes, what we call strings, Rollo doesn't care whether you use uppercase letters or lowercase letters. Even when it comes to the strings used to specify colors, Rollo still doesn't care.
All of the following commands are valid and mean the same thing:
rIGhT
right
RIGHT
Right
Optional Parameters
Commands that take parameters often take optional units for those parameters that may be omitted:
wait 1
wait 1 second
Those two lines are equivilent. Basically units (seconds, degrees, times, %, and such) are ignored, so you can use them if they help make more sense to you, but Rollo doesn't care either way.
Words (strings) versus Numbers
Numbers and words are handled differently in Rollo, as in most languages. If a parameter that you are giving to a command is a number, you can just type in the number (and the optional units). If the parameter is made up of words, though, you have to put them in quotes. You can use single or double quotes:
color 'green'
color "orange"
Both of those set the Sphero's color and work fine. This one, however, is not fine:
color 'green"
You can't mix and match quotes. If you start with a ', you must end with '. The same goes for ".
It might seem silly to have to put quotes around word parameters like 'green' and 'orange', but it makes more sense when your words have spaces in them:
say "This will show up on the output log"
The say command, for instance, can have full sentences passed to it, which then get displayed in the output log. If we didn't have the quotes, it would make something like the following hard for Rollo to interpret:
say We are going to wait 1 second
Rollo would get confused without the quotes because it would see the "wait 1 second" and might think it was a command. The quotes tell Rollo that the words all belong together, even it contains spaces or some of the words are actually numbers.
Command Blocks
There are some commands, like 'repeat' and 'if' (among others) that make use of curly braces to show that they control a block, or group, of commands:
repeat 2 times {
right
wait 1 second
}
This tells Rollo to turn right and wait a second, and do that process twice. The indentation for the lines inside the curly braces is entirely optional, but it makes the code much easier to read if you use some form of consistent indentation.
Rollo is pretty flexible on where you place your curly braces. You can put them on the same line as an expression like this:
if $var < 4 {
color 'red'
} else {
color 'green'
}
Or you can put them on their own lines, as in this example:
if $var < 4
{
color 'red'
}
else
{
color 'green'
}
You can even indent them as you please:
if $var < 4
{
color 'red'
}
else
{
color 'green'
}
But however you decide to do it, you should always do it the same way. This makes your program easier for everybody, including you, to read.
Expressions
Expressions in Rollo are basically math questions. The simplest example is probably this:
1
It is a valid math expression that has the value of 1. Expressions become more useful, though, when combined with math operators and multiple numbers. Take a look at this example, which has the value of 5:
2 + 3 * (5 - 3) / 2
That expression means "2 plus 3 times the difference of 5 and 3, divided by 2". Just keep in mind that multiplication and division get done before addition and subtraction in general, but that parentheses come first. That's just regular math rules, not part of Rollo. So you might want to think of that expression as saying "Take 5 - 3 and multiply the difference by 3 and then divide it by 2 and add 2"
Rollo currently only supports '+', '-', '*', and '/' for expressions.
Variables
A variable in Rollo is a name that starts with a dollar sign ($) that holds a value. Using the Let command, you can assign the value of an expression to a variable. Variables can be used in expressions, as well, so that you could create an expression that uses both numbers and other variables to assign the value to another variable:
let $myVar = $someVar + 2
If $someVar had the value of 3, then $myVar would end up holding a value of 5, since 3 + 2 is 5. If $someVar were 0, then $myVar would be 2, and so on.
If you refer to a variable that has not had a value assigned to it with a let command, then it will automatically start out with a value of 0.
Condition Expressions
You might have noticed that the 'if' command examples in the Command Blocks section have an expression after the 'if' that makes use of comparisons. Those are examples of condition expressions in Rollo.
Condition Expressions can make use of the following comparison operators:
Equality: == or === or equal to or equals
Inequality: != or !== or not equal or not equals
Less than or equal: <=
Greater than or equal: >=
Less than: < or less than
Greater than: > or greater than OR more than
You can also use 'is' before the comparison. So these are all valid and mean the same thing:
2 == 1 + 1
2 === 3 - 1
2 is equal to 6 / 3
2 equals 5 - 3
You can even do the following, though it looks quite strange:
2 is == 8 / (2 * 2)
Any valid Rollo expression can be used in a comparison, which means that variables and functions are also allowed:
let $speedLimit = 50
if speed() > $speedLimit {
say "We're going too fast!"
}
That code will use the say command to warn us if the Sphero is going over 50% of its max speed, since 50 is the value given to $speedLimit.
Subroutines
There are also subroutines in Rollo. A subroutine is a group of lines that have a label (or name) associated with it that can then be run by referring to that name. For example.
sub myStuff {
flash 'red'
wait 2 seconds
}
This defines a block of sub (a block of code) called "myStuff" that can be run with the gosub command:
color 'blue'
go
repeat 6 times {
gosub myStuff
}
color 'green'
stop
sub myStuff {
right
flash 'red'
wait 2 seconds
}
What this will do is change the sphero's color to blue, start rolling, and then call the sub myStuff 6 times. Each time myStuff is called with the gosub command, the sphero will turn right, flash red, and then wait 2 seconds. Finally, the sphero will turn green and stop rolling after myStuff has been run the sixth time.
The above program does exactly the same thing as the following, but is shorter and easier to read than this mess:
color 'blue'
go
right
flash 'red'
wait 2 seconds
right
flash 'red'
wait 2 seconds
right
flash 'red'
wait 2 seconds
right
flash 'red'
wait 2 seconds
right
flash 'red'
wait 2 seconds
right
flash 'red'
wait 2 seconds
color 'green'
stop
Subs can be put anywhere in your program as long as they are not inside a block. The gosub command that calls a sub can, of course, be inside a block. With that in mind, consider the following examples:
This is valid
sub myStuff {
flash 'red'
wait 2 seconds
}
color 'blue'
repeat 3 times {
gosub myStuff
}
color 'green'
This is valid, too, and does the exact same thing
color 'blue'
repeat 3 times {
gosub myStuff
}
color 'green'
sub myStuff {
flash 'red'
wait 2 seconds
}
This is NOT valid because the sub is inside the repeat block
color 'blue'
repeat 3 times {
gosub myStuff
sub myStuff {
flash 'red'
wait 2 seconds
}
}
color 'green'
Rollo commands
The commands that you can use in a Rollo program are listed below. I've tried to group them logically.
Each command is followed by the type of parameters it requires. As an example, consider the fictional command definition below:
glorb duration:number [color:string|color:number]
This means that the glorb command requires a number of seconds to be provided as a duration. Anything inside square bracketc [ ] is optional.
And anything separated by a vertical line means 'or'. So in this case you can, if you like, supply a second parameter that will be
the color glorb should use, and you can either specify the color as a string like 'blue' or as a number like 255.
The real commands are as follows:
Movement
GO
go [duration:number]
Makes the sphero start rolling. If no duration is specified, it will keep going until stopped with a stop command. If a duration is
given, then it will automatically stop after that many seconds have passed.
LEFT
left [degrees:number]
As with right, changes the current or next heading of the Sphero, except in the opposite direction. For example, "left 45" will cause the Sphero to veer to the left. If no degree parameter is specified, the Sphero will turn 90 degrees.
Alias: turnLeft
REVERSE
reverse
Causes the Sphero's heading to shift 180 degrees so that it will move in the opposite direction from where it is currently heading.
Alias: turnAround
RIGHT
right [degrees:number]
Changes the current or next heading of the Sphero. Accepts only positive numbers. For example, "right 45" will cause the Sphero to veer off to the right. If no degree parameter is specified, the Sphero will turn 90 degrees.
Alias: turnRight
SPEED
speed percent:number
Sets the percentage of full speed the sphero will use when moving
STOP
stop
Sets the Sphero's speed to 0, causing it to stop. If the Sphero is moving quickly at the time, the stop will not be instant.
TURN
turn degrees:number
Changes the heading that the Sphero is travelling. If moving, it will cause an immediate turn. If still, it will adjust the heading used the next time the Sphero moves. The degrees can be specified as a postive (clockwiswe) number or as a negative (counterclockwise) number.
Variable Assignment
LET
let name:variable_label = expression
The let commands allows a value to be assigned to a numeric variable. All numeric variables in Rollo must start with the $ character and be followed by one or more letters or numbers. The expression that is evaluated and assigned to the variable can consist of numbers or other variables and make use of addition, subtraction, multiplication, and division. Parenthese may also be used.
Consider the following example, which assigns the value of $someVar times 2, plus 15 more to the variable $myVar:
let $myVar = 2*$someVar + 15
Expressions need not be complex. For example, the following line of code assigns the value in $myVar to a variable called $backup:
let $backup = $myVar
Flow Control
DO ... UNTIL
do { block-of-commands } until condition:expression
The do ... until command can be thought of as a combination of the if and repeat commands. The code inside of the block will continue to repeat as long as the condition specified is not true. That is the opposite effect of the while and do ... while loops! Another thing to pay attention to is that no matter what the expression is, the block of code will always execute at least once. The following example will cause the Sphero to move and turn three times:
let $index = 1
do {
go 1 second
left 45 degrees
let $index = $index + 1
} until $index > 3
It does so by increasing the value of $index by one each time through the loop, which causes the do ... until loop to stop after running three times. The first time the condition is checked, $index will have a value of 2 since it starts at 1 and gets one added to it each time through the loop. When the do ... until finishes, $index will have a value of 4. If we hadn't set the initial value of $index to 1 in the first line, the loop would have run 4 times since uninitialized variables get a default value of 0.
In most cases you will want to use the while loop instead of do ... until, as you will only want the block of code to run if the comparison condition is true. Use do ... until only when you want the block to run one time no matter what.
DO ... WHILE
do { block-of-commands } while condition:expression
The do ... while command can be thought of as a combination of the if and repeat commands. The code inside of the block will continue to repeat as long as the condition specified evaluates to true. The trick to pay attention to is that no matter what the expression is, the block of code will always execute at least once. The following example will cause the Sphero to move and turn three times:
let $index = 1
do {
go 1 second
left 45 degrees
let $index = $index + 1
} while $index < 4
It does so by increasing the value of $index by one each time through the loop, which causes the do ... while loop to stop after running three times. The first time the condition is checked, $index will have a value of 2 since it starts at 1 and gets one added to it each time through the loop. When the do ... until finishes, $index will have a value of 4. If we hadn't set the initial value of $index to 1 in the first line, the loop would have run 4 times since uninitialized variables get a default value of 0.
In most cases you will want to use the while loop instead of do ... while, as you will only want the block of code to run if the comparison condition is true. Use do ... while only when you want the block to run one time no matter what.
GOSUB
gosub name:sub_label
Causes Rollo to execute the named sub one time. Unlike strings, labels should not be enclosed inside of double or single quotes.
Alias: call
IF
if condition:expression { block-of-commands }
The if command allows a block of commands to be executed only if the expression passed to it is evaluated to be true. Consider the following example, which will set the Sphero's color to yellow only if the value of the variable $test is greater than 10:
if $test > 10 {
color 'yellow'
}
Condition expressions consist of two mathematical expressions (which may or may not make use of variables) separated by a comparison operator. This means the previous example could be written like the following:
if $test * 2 > 10 + $anotherVar {
color 'yellow'
}
IF ELSE
if condition:expression { block-of-commands } else { block-of-commands }
Same as the regular if command, except that there is a second block of lines that is run if the if condition expression is false. Consider the following example, which will set the Sphero's color to yellow if the value of the variable $test is greater than 10, otherwise it will set the color to red:
if $test > 10 {
color 'yellow'
} else {
color 'red'
}
REPEAT
repeat count:number { block-of-commands }
The repeat command causes the group of lines inside the curly braces { } to be repeated the specified number of times. For example, the following will cause the Sphero to drive in a square:
repeat 4 times {
go 2
right
}
Alias: loop
SUB
sub name:sub_label { block-of-commands }
The sub command defines a named block of commands that can be executed by using the gosub command. The sub command can only be used in the root level of the Rollo program, meaning that it cannot be used inside of any sort of block of code (though the gosub command that calls it certainly can). Unlike with strings, a label should have neither single nor double quotes around it.
Here's an example sub named 'mySub' that causes the Sphero to go straight and then turn around.
sub mySub {
go 1
reverse
}
#####WAIT
wait duration:number
Tells Rollo to wait for a specified number of seconds before continuing.
wait 2 seconds
Alias: delay
WAITFORTAP
waitForTap [timeout:number]
Causes the Rollo to wait until the Sphero has been hit by something (like a hand) or runs solidly into something (like a wall). The optional timeout parameter tells Rollo how many seconds it should wait for a tap before it gives up and moves on to the next command.
waitForTap 8 seconds
Alias: waitForHit
WHILE
while condition:expression { block-of-commands }
The while command can be thought of as a combination of the if and repeat commands. The code inside of the block will continue to repeat as long as the condition specified evaluates to true. The following example will cause the Sphero to move and turn three times:
let $index = 1
while $index < 4 {
go 1 second
left 45 degrees
let $index = $index + 1
}
It does so by increasing the value of $index by one each time through the loop, which causes the while loop to stop after running three times. If we hadn't set the initial value of $index to 1 in the first line, the loop would have run 4 times since uninitialized variables get a default value of 0.
See if for more information on comparison expressions.
Color
COLOR
color color-name:string|color-value:hexadecimal
Sets the color of the Sphero. If supplied a known string, such as "red" or 'green' or 'darkblue', Rollo will change the Sphero color accordingly. If supplied a hexadecimal number, it will change to the color specified by the value. Rollo understands HTML CSS-like colors, in that 0xff0000 is red, 0x00ff00 is green, and 0x0000ff is blue.
To set the Sphero to purple, you would use either of the following commands:
color 'purple'
color 0x800080
Rollo currently understands the following colors: red, darkred, green, darkgreen, blue, darkblue, orange, darkorange, purple, darkpurple, yellow, darkyellow, white, gray, darkgray, or none or off for no light at all.
FLASH
flash color-name:string|color-value:hexadecimal
Causes the Sphero to shine the specified color for one second before reverting back to its original color. Unlike most commands in Rollo that have a duration, the flash command does not cause Rollo to wait for it to finish before it proceeds. This means that you can issue a flash on an impact, for example, and the color change will take place while you might be instructing Rollo to reverse direction.
Flash uses the same color parameters as the color command.
PULSE
pulse color-name:string|color-value:hexadecimal
Nearly identical to flash, except that the chosen color fades in and out for a more subtle effect.
Pulse uses the same color parameters as the color command.
Utility
POINTME
pointMe
Causes the Sphero to go into calibration mode with a blue light shining in the opposite direction that it will move. Calibration mode is automatically stopped once a go command is received. It is often useful to follow the pointMe command with a waitForTap command so that the Sphero can be oriented and then tapped to tell the Rollo program to continue. For example:
pointMe
waitForTap 6
go 3
This example will cause the Sphero to go into calibration mode and wait for a tap for a maximum of 6 seconds. When tapped or the 6 second timeout expires, it will then proceed to go for three seconds (straight ahead).
Alias: ALIAS
SAY
say text:string
The say command causes Rollo to output text. This can be used to help with debugging.
say 'This will go to the log'
Alias: log
Rollo Functions
Rollo supports a handful of built-in functions that you can use in expressions. They can be used to assign a value to a variable, in a comparison, or as part of a math expression.
HEADING
getHeading()
Returns the current direction of the Sphero. 0 is the point that the Sphero was facing when the program started, 180 is the opposite direction.
Consider the following example, which sets the color of the Sphero to purple and then checks whether the heading is more than 180 degrees and, if so, sets the color instead to orange.
color 'purple'
if getHeading() > 180 {
color 'orange'
}
SPEED
getSpeed()
Returns the current rolling speed of the Sphero. 0 is stopped (or in the process of stopping), 100 is full speed.
The following code will set the speed to 50 and mame the Sphero roll for a second at that speed. It will then loop, decreasing speed by 5 each time through the loop, as long as the speed is great than 25. Once through the loop, it will stop.
speed 50
go 1
while getSpeed() > 25 {
let $speed = getSpeed() - 5
speed $speed
go 1
}
stop
DEFAULT SPEED
getDefaultSpeed()
Returns the default speed of the Sphero. This is the speed that the Rollo will move at the next time it starts rolling (assuming that a speed command is not later used).
if defaultSpeed() == 100 {
say "Full speed ahead!"
}