Home ← STEM HQ ← TI-Nspire Authoring ← TI-Nspire Scripting HQ ← Scripting Tutorial - Lesson 45
Scripting Tutorial - Lesson 45: Lua Scripting and the TI Innovator™ Hub:
5. Lua Script for the TI Innovator™ Hub Rover
TI Innovator™ Hub Lesson 0: Using Lua to store and edit TI-BASIC programs for the Innovator™ Hub (Lua Scripting Lesson 40)
TI Innovator™ Hub Lesson 1: SENDING to the Hub: Controlling the Action (Lua Scripting Lesson 41)
TI Innovator™ Hub Lesson 2: READING from the Hub: Real world interaction and data (Lua Scripting Lesson 42)
TI Innovator™ Hub Lesson 3: Exploring the OneShotTimer: Learning to Wait! (Lua Scripting Lesson 43)
TI Innovator™ Hub Lesson 4: Making Music with the Innovator™ Hub (Lua Scripting Lesson 44)
TI Innovator™ Hub Lesson 5: Lua Script for the TI Innovator™ Hub Rover (Lua Scripting Lesson 45)
TI Innovator™ Hub Lesson 6: Lua Script for the Norland Research/TI Innovator™ Hub Robot (Lua Scripting Lesson 46)
TI Innovator™ Hub Lesson 7: Build your own Innovator™ Hub Robot (Lua Scripting Lesson 47)
TI Innovator™ Hub Lesson 8: Create a general Innovator™ Hub Document (Lua Scripting Lesson 48)
TI Innovator™ Hub Lesson 9: Create a general Innovator™ Hub and BLE Document (Lua Scripting Lesson 49)
Download supporting file 1 for this tutorial: Lua_Rover.tns
Download supporting file 2 for this tutorial: TI_Rover_BASIC_Sampler.tns
All about the TI Innovator™ Rover
Texas Instruments TI-Nspire Scripting Support Page
Scripting for the Innovator Hub: Lesson 5: Lua Script for the TI Innovator™ Rover
Multiple Pathways to Controlling a RobotThis lesson and the two that follow describe three different approaches to working with robot vehicles. This lesson introduces the TI Innovator™ Hub Rover, and the next, the Norland E3 Innovator™ Robot - both built on the amazing TI Innovator™ Hub. The third lesson describes building a robot from just a TI LaunchPad board (or a "hacked" Innovator Hub!)
The TI Rover offers the simplest possible access to robotics for students. The TI-BASIC coding language, ideal for students from middle years upwards, has been enhanced with commands specific to the Rover. Connecting the varied sensors and functionality of the vehicle to the Innovator Hub is as simple as "CONNECT RV". Have a peek at the next lesson and compare this to the Norland robot, without the custom commands, which instead uses the generalised DIGITAL.IN/OUT and ANALOG.IN/OUT commands, all of which must be connected individually to the BB ports of the Hub.
Note, however, that while this simplicity makes it quick and easy for students to work with the Rover, it also masks what is actually happening in the background. Those who are interested to go further with robotics may well derive benefit from experimenting, as I did, to find the various connections which link the BB ports to the drive motors (BB4, BB8, BB9, BB10), the HC-SR04 ultrasonic sensor (BB6 TRIG and BB5 ECHO) and colour input sensor (BB3 for the Colour Sensor white LED and I2C for the Adafruit TCS34725). Further investigation is required to see how the gyroscope is connected.
Below, you will find both simple TI-BASIC programs as well as the full Lua script which may be used to control the TI-Innovator Hub Rover. If the student focus is upon simple coding, then TI-BASIC offers a great solution. You will find in the downloads for this tutorial a TI Rover BASIC Sampler written using Lua. As outlined in Tutorial 40, this can offer a very convenient way for students to easily access the various TI-BASIC programs required to run the robot, but also, more importantly, the means by which they can quickly and easily edit and explore these programs, instantly trying out their changes to see the effect.
The Lua script offers the same control features as the TI-BASIC examples, plus other options for drawing on the power of the Hub.
A range of new settings variables are added, allowing the user to control such features as robot speed, run time, timer step, etc. Take note of the use of var.monitor and on.varChange which will update the script immediately any change occurs in these monitored values.
These may be stored for convenience in a spreadsheet on page 1.2.
On-screen instructions are included in on.paint, and on.resize serves as a full reset function (coupled with on.escapeKey).
Study the graphical controller for the robot, which works neatly with the arrow keys.
Note the changes to mouseDown and mouseUp.
Note also the utility function str2list which allows easy separation of Hub rxValues which may not always be numeric.
are defined here: individually for the four directions, and then the autoDrive function and a nice Polygon function.
- OneShotTimer is added to the Innovator functions, which are otherwise unchanged.
At this point, it is also instructive to compare the Lua functions we are defining to their TI-BASIC counterparts.
Define fd(time)=Prgm
Send "CONNECT RV "EndPrgm
Disp "FORWARD "&string(time)&" s"
Send "SET RV FORWARD "&string(time)
wait time
Send "DISCONNECT RV "
Define bk(time)=Prgm
Send "CONNECT RV "EndPrgm
Disp "BACKWARD "&string(time)&" s"
Send "SET RV BACKWARD "&string(time)
wait time
Send "DISCONNECT RV "
Define lt(angle)=Prgm
Send "CONNECT RV "EndPrgm
Disp "LEFT "&string(angle)&" DEGREES"
Send "SET RV LEFT "&string(angle)
wait 0.2
Send "DISCONNECT RV "
Define rt(angle)=Prgm
Send "CONNECT RV "EndPrgm
Disp "RIGHT "&string(angle)&" DEGREES"
Send "SET RV RIGHT "&string(angle)
wait 0.2
Send "DISCONNECT RV "
Define polygons()=Prgm
Local m,n,iEndPrgm
Send "CONNECT RV"
Request "side length (cm)",n
Request "no. sides",m
n:=((n)/(20))
For i,1,m
Send "RV FORWARD SPEED .2 M/S TIME eval(n)"EndFor
Send "RV LEFT eval(360/m) DEGREES"
Define auto()=Prgm
Local dEndPrgm
d:=0
Send "CONNECT RV "
Wait 0.2
Send "READ RV.RANGER "
Get d
Disp "Distance: "&string(d)&" m"
Send "SET SOUND eval(d*1000) 0.5"
Wait 0.2
While d>0.1
Send "READ RV.RANGER "
Get d
Disp "Distance: "&string(d)&" m"
Send "SET SOUND eval(d*1000) 0.5"
Wait 0.2
If d>0.3 Then
Send "SET RV FORWARD 1"
Else
Send "SET RV BACKWARD 0.5"
Send "SET RV RIGHT 15"
EndIf
EndWhile
Send "DISCONNECT RV "
-- TI Innovator Init Values
platform.apilevel = '2.7'
local screen = platform.window
local date = "180318"require 'color'
pcall(function() require 'asi' end)local hubStrOn, hubStrOff, msgStr, rxValue, timeStr, repeats, time_step, delay
local list1, list2, index, dataList = {}, {}, {}, {}
var.store("index", index)
var.store("dataList", dataList)
local oldChar = ''
local help = 1
local fontSize = 20local robotConnected = false
local time_step = var.recall("time_step") or 0.5
local runTime = var.recall("runtime") or 10
local runtimeStr = "Run Time: "..runTime
local robotSpeed = var.recall("speed") or 10
local speedStr = "Robot Speed: "..robotSpeed.." cm/s"
local colornames = {"red","green","blue","cyan","magenta","yellow","black","white","gray"}var.monitor("speed")
var.monitor("runtime")
var.monitor("time_step")
var.monitor("hubstr")
var.monitor("polysides")
var.monitor("polylength")function on.varChange(varList)
robotSpeed = var.recall("speed") or 10end
speedStr = "Robot Speed: "..robotSpeed.." cm/s"
runTime = var.recall("runtime") or 10
runtimeStr = "Run Time: "..runTime
time_step = var.recall("time_step") or 0.5
local colornames = {"red","green","blue","cyan","magenta","yellow","black","white","gray"}
polysides = var.recall("polysides") or 5
polylength = var.recall("polylength") or 20
hubStrOn = string.upper(var.recall("hubstr")) or ''
if hubStrOn:find("ON") then
hubStrOff = hubStrOn:gsub("ON","OFF")else
TI_Innovator.Send(hubStrOn)
addMsg(hubStrOn)
hubStrOff = ''end
TI_Innovator.Send(hubStrOn)
addMsg(hubStrOn)
if hubStrOn:find("READ") then TI_Innovator.Read() end
screen:invalidate()
function addMsg(input)
msgStr = input
print(msgStr)
screen:invalidate()end
function on.construction()
end--the next three lines are required for Hub connection
TI_Innovator.init(TI_InnovatorStateCallback)
TI_Innovator.setReadListener(TI_InnovatorReadCallback)
TI_Innovator.connect()Menu={
{"About",}
{" ©2018 Compass Learning Technologies", function() end},},
{" Version "..date, function() end},
{" Contact: steve@compasstech.com.au ", function() end},
{" Help?", function() on.help() end},
{"Controls",
{"Scan and Connect", function() TI_Innovator.connect() end},},
{"Disconnect", function() TI_Innovator.disconnect() on.resize() end},
{"RESET", function() on.resize() end},
{"SET Samples",
{"SET LIGHT ON/OFF (default)", function() hubStrOn = "SET LIGHT ON" hubStrOff = "SET LIGHT OFF" TI_Innovator.Send(hubStrOn) addMsg(hubStrOn) rxValue = "Press mouse down to toggle light" end},
{"SET COLOR.RED ON/OFF", function() hubStrOn = "SET COLOR.RED ON" hubStrOff = "SET COLOR.RED OFF" TI_Innovator.Send(hubStrOn) addMsg(hubStrOn) rxValue = "Press mouse down to toggle red LED" end},
{"SET COLOR.GREEN ON/OFF", function() hubStrOn = "SET COLOR.GREEN ON" hubStrOff = "SET COLOR.GREEN OFF" TI_Innovator.Send(hubStrOn) addMsg(hubStrOn) rxValue = "Press mouse down to toggle green LED" end},
{"SET COLOR.BLUE ON/OFF", function() hubStrOn = "SET COLOR.BLUE ON" hubStrOff = "SET COLOR.BLUE OFF" TI_Innovator.Send(hubStrOn) addMsg(hubStrOn) rxValue = "Press mouse down to toggle blue LED" end},
{"SET SOUND 220 1", function() hubStrOn = "SET SOUND 220 1" hubStrOff = "SET SOUND 0 1" TI_Innovator.Send(hubStrOn) addMsg(hubStrOn) rxValue = "Press mouse down to repeat sound" end},
{'_________________', function() end},
{"SET SPEAKER 1 220 5", function() hubStrOn = "SET SPEAKER 1 220 5" TI_Innovator.Send("CONNECT SPEAKER 1 OUT1") TI_Innovator.Send(hubStrOn) hubStrOff = "SET SPEAKER 1 0 1" rxValue = "Press mouse down to toggle speaker" end},
{"SET LED 1 ON", function() hubStrOn = "SET LED 1 ON" TI_Innovator.Send("CONNECT LED 1 OUT1") TI_Innovator.Send(hubStrOn) hubStrOff = "SET LED 1 0FF" rxValue = "Press mouse down to toggle LED" end},
{"SET SERVO 1 CW 50 5 (OUT3)", function() TI_Innovator.Send("CONNECT SERVO 1 OUT3") hubStrOn = "SET SERVO 1 CW 50 5" hubStrOff = "SET SERVO 1 CW 50 0" rxValue = "Press mouse down to toggle servo" end},
{"SET ANALOG.OUT 1 100", function() hubStrOn = "SET ANALOG.OUT 1 100" TI_Innovator.Send("CONNECT ANALOG.OUT 1 OUT1") TI_Innovator.Send(hubStrOn) hubStrOff = "SET ANALOG.OUT 1 0" rxValue = "Press mouse down to toggle analog read" end},
{"SET DIGITAL.OUT 1 ON", function() hubStrOn = "SET DIGITAL.OUT 1 ON" TI_Innovator.Send("CONNECT DIGITAL.OUT 1 OUT1") TI_Innovator.Send(hubStrOn) hubStrOff = "SET DIGITAL.OUT 1 0FF" rxValue = "Press mouse down to toggle digital read" end},
},
{"READ Samples",
{"READ BRIGHTNESS (b)", function() hubStrOn = "READ BRIGHTNESS" TI_Innovator.Send(hubStrOn) TI_Innovator.Read() timeStr = "Press mouse down to take fresh reading" end},},
{'_________________', function() end},
{"READ RV SWITCH (s)", function() hubStrOn = "READ RV SWITCH" TI_Innovator.Send(hubStrOn) TI_Innovator.Read() hubStrOff = '' timeStr = "Press mouse down to take fresh reading" end},
{"READ RV.RANGER (r)", function() robotConnect() hubStrOn = "READ RV.RANGER" TI_Innovator.Send(hubStrOn) TI_Innovator.Read() hubStrOff = '' timeStr = "Press mouse down to take fresh reading" end},
{"READ RV.COLORINPUT (c)", function() robotConnect() hubStrOn = "READ RV.COLORINPUT" TI_Innovator.Send(hubStrOn) TI_Innovator.Read() hubStrOff = '' timeStr = "Press mouse down to take fresh reading" end},
{'_________________', function() end},
{"READ RANGER 1", function() hubStrOn = "READ RANGER 1" TI_Innovator.Send("CONNECT RANGER 1 IN1") math.eval("wait(0.5)") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() hubStrOff = '' timeStr = "Press mouse down to take fresh reading" end},
{"READ ANALOG.IN 1", function() hubStrOn = "READ ANALOG.IN 1" TI_Innovator.Send("CONNECT ANALOG.IN 1 IN1") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() hubStrOff = '' timeStr = "Press mouse down to take fresh reading" driver = "ANALOG.IN 1" driverConnected = true end},
{"READ DIGITAL.IN 1", function() hubStrOn = "READ DIGITAL.IN 1" TI_Innovator.Send("CONNECT DIGITAL.IN 1 IN1") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() hubStrOff = '' timeStr = "Press mouse down to take fresh reading" driver = "DIGITAL.IN 1" driverConnected = true end},
{"Sound Samples",
{"C4", function() hubStrOn = "SET SOUND 262 TIME 1" TI_Innovator.Send(hubStrOn) hubStrOff = "SET SOUND 0 1" msgStr = hubStrOff rxValue = "Press mouse down to play sound" end},},
{"A4", function() hubStrOn = "SET SOUND 440 TIME 1" TI_Innovator.Send(hubStrOn) hubStrOff = "SET SOUND 0 1" msgStr = hubStrOff rxValue = "Press mouse down to play sound" end},
{"C5", function() hubStrOn = "SET SOUND 523 TIME 1" TI_Innovator.Send(hubStrOn) hubStrOff = "SET SOUND 0 1" msgStr = hubStrOff rxValue = "Press mouse down to play sound" end},
{"No tone", function() hubStrOn = "SET SOUND 0 TIME 1" TI_Innovator.Send(hubStrOn) hubStrOff = "SET SOUND 0 1" msgStr = hubStrOff end},
{"Aliens (sample)", function() tempo = 1000 I=1 list1 = notes_aliens list2 = times_aliens playTone(list1,list2) rxValue = "Aliens" end},
{"BallGame (sample)", function() tempo = 1000 I=1 list1 = notes_bgame list2 = times_bgame playTone(list1,list2) rxValue = "Take me out to the Ball Game" end},
{"Happy Birthday (sample)", function() tempo = 1000 I=1 list1 = notes_bday list2 = times_bday playTone(list1,list2) rxValue = "Happy Birthday" end}, {"If I Only Had a Brain (sample)", function() tempo = 4000 I=1 list1 = notes_brain list2 = times_brain playTone(list1,list2) rxValue = "If I only had a brain" end},
{"Fur Elise (sample)", function() tempo = 1000 I=1 list1 = notes_elise list2 = times_elise playTone(list1,list2) rxValue = "Fur Elise" end},
{"Home on the Range (sample)", function() tempo = 1000 I=1 list1 = notes_home list2 = times_home playTone(list1,list2) rxValue = "Home on the Range" end},
{"Well-tempered Scale", function() tempo = 1000 I=1 list1 = notes_welltemp list2 = times_scale playTone(list1,list2) rxValue = "Well tempered scale" end},
{"Harmonic Scale", function() tempo = 1000 I=1 list1 = notes_harmonic list2 = times_scale playTone(list1,list2) rxValue = "Harmonic scale" end},
{"Robot Samples",
{"CONNECT RV (enter)", function() robotConnect() end},},
{"DISCONNECT RV (d)", function() robotDisconnect() end},
{"READ RV SWITCH (s)", function() hubStrOn = "READ RV SWITCH" TI_Innovator.Send(hubStrOn) TI_Innovator.Read() hubStrOff = '' timeStr = "Press mouse down to take fresh reading" end},
{"ROBOT FD runTime", function() fd(runTime) end},
{"ROBOT BK runTime", function() bk(runTime) end},
{"ROBOT LT 0.5 secs", function() lt(45) end},
{"ROBOT RT 0.5 secs", function() rt(45) end},
{"autoDrive (a)", function() autoDrive() end},
{"poly(polysides,polylength) (p)", function() polysides = var.recall("polysides") or 5 polylength = var.recall("polylength") or 20 poly(polysides, polylength) end},
{"TIMER Samples",
{"wait(runTime) (w)", function() wait(runTime) end},},
{"blink(runTime,1)", function() blink(runTime,1) end},
{"alarm(runTime,0.5)", function() alarm(runTime,0.5) end},
toolpalette.register(Menu)
screen:invalidate()
-- Layout Functions
function on.resize(width, height)
w = screen:width()end
h = screen:height()
hubStrOn, hubStrOff, msgStr, rxValue, timeStr = "", "", "", "", ""
var.store("hubstr", hubStrOn)
delay, num, sl, repeats, oldChar = 0, 0, 0, 0, 0.1, 1, ""
tempo, key, I = 1000, 0, 1 time_step = var.recall("time_step") or 0.5
robotSpeed = var.recall("speed") or 10
speedStr = "Robot Speed: "..robotSpeed.." cm/s"
runTime = var.recall("runtime") or 10
fontSize = math.floor(h/20 + 0.5)
if hh then
fontSize = fontSize > 7 and fontSize or 7end
fontSize = fontSize < 24 and fontSize or 24
fontSize1 = math.floor(h/30 + 0.5)
if hh then
fontSize = fontSize > 7 and fontSize or 7end
fontSize = fontSize < 24 and fontSize or 24
list1, list2, index, dataList = {}, {}, {}, {}
var.store("index", index)
var.store("dataList", dataList)
robotControls = rc(0.5*w, 0.5*h, 0.15*h, false, true)
if TI_Innovator.isConnected() then
addMsg("TI Innovator Hub ready")end
function on.paint (gc)
gc:setFont("sansserif", "r", fontSize)end
if TI_Innovator.isConnected() then gc:setColorRGB(0,255,0) else gc:setColorRGB(255,0,0) end
if TI_Innovator.isConnected() or help == 0 then
gc:fillRect (0, 0, w, 0.025*h)else
local sw = gc:getStringWidth(runtimeStr)
gc:drawString(runtimeStr, 0.9*w - sw, 0.1*h, "middle")
local sw = gc:getStringWidth(speedStr)
gc:drawString(speedStr, 0.965*w - sw, 0.2*h, "middle")
robotControls:paint(gc)
gc:fillRect (0, 0, w, 0.025*h)end
gc:drawString("Wait for connection, then", 0.025*w, 0.1*h, "middle")
gc:drawString("press anywhere to activate Hub", 0.025*w, 0.2*h, "middle")
gc:setFont("sansserif", "r", fontSize1)
gc:drawString("Change settings (speed,runTime,polysides,polylength) or enter ", 0.025*w, 0.3*h, "middle")
gc:drawString("new hub commands (hubStr) using the spreadsheet on the next page", 0.025*w, 0.35*h, "middle")
gc:drawString("Press 'a' for AUTODRIVE ", 0.025*w, 0.45*h, "middle")
gc:drawString("Press 'b' to read BRIGHTNESS ", 0.025*w, 0.5*h, "middle")
gc:drawString("Press 'c' to read RV.COLORINPUT ", 0.025*w, 0.55*h, "middle")
gc:drawString("Press 'p' for Polygon ", 0.025*w, 0.6*h, "middle")
gc:drawString("Press 'r' to READ RV.RANGER ", 0.025*w, 0.65*h, "middle")
gc:drawString("Press 's' to READ RV.SWITCH ", 0.025*w, 0.7*h, "middle")
gc:drawString("Press 'w' to wait ", 0.025*w, 0.75*h, "middle")
gc:drawString("Press 'enter' to CONNECT RV ", 0.025*w, 0.8*h, "middle")
gc:drawString("Press 'd' to DISCONNECT ", 0.025*w, 0.85*h, "middle")
if TI_Innovator.isConnected() then gc:setColorRGB(0,255,0) else gc:setColorRGB(255,0,0) end
gc:setFont("sansserif", "r", fontSize)
gc:drawString(timeStr, 0.025*w, 0.8*h, "middle")
gc:drawString(msgStr, 0.025*w, 0.875*h, "middle")
gc:drawString(rxValue, 0.025*w, 0.95*h, "middle")
gc:setFont("sansserif", "r", fontSize1)
gc:setColorRGB(0, 0, 255)
local str = "TI Innovator Rover Disconnected"
if TI_Innovator.isConnected() and robotConnected then str = "Rover connected" end
local sw = gc:getStringWidth(str)
gc:drawString(str, 0.975*w - sw, 0.95*h, "middle")
rc = class()
function robotConnect()
pcall(function()end
TI_Innovator.Send('BEGIN\n')end)
robotControls.visible = true
TI_Innovator.Send("CONNECT RV")
hubStrOn = "READ RV SWITCH"
var.store("hubstr", hubStrOn)
wait(0.5)
help = 0
TI_Innovator.Send(hubStrOn)
TI_Innovator.Read()
screen:invalidate()
function robotDisconnect()
pcall(function()end
TI_Innovator.Send('BEGIN')end)
robotConnected = false
hubStrOn = 'DISCONNECT RV'
hubStrOff = ''
delay = 0
help = 1
runTime = var.recall("runtime") or 10
var.store("hubstr", hubStrOn)
screen:invalidate()
function rc:init(x, y, width, selected, visible)
self.x = xend
self.y = y
self.width = width
self.height = width
self.visible = visible
self.selected = selected
function rc:contains(x, y)
local sw = self.width or self.heightend
local sh = self.height or self.width
return x >= self.x - 1.5*sw and x <= self.x + 1.5*sw and
y >= self.y - 1.5*sh and y <= self.y + 1.5*sh
function rc:paint(gc)
w = screen:width()end
h = screen:height()
if self.visible == true then
local x = self.xend
local y = self.y
local width = self.width
local height = self.width
gc:setPen("thin", "smooth")
if self.selected and hubStrOn:find("BACK") then
gc:setPen("medium", "smooth")else
gc:setPen("thin", "smooth")end
local upArrow = {x - 0.5*width, y - 0.5*height, x, y - 1.5*height, x + 0.5*width, y - 0.5*height, x - 0.5*width, y - 0.5*height}
gc:setColorRGB(0,0,255)
gc:fillPolygon(upArrow)
gc:setColorRGB(color.black)
gc:drawPolyLine(upArrow)
if self.selected and hubStrOn:find("RIGHT") then
gc:setPen("medium", "smooth")else
gc:setPen("thin", "smooth")end
local leftArrow = {x - 1.5*width, y, x - 0.5*width, y - 0.5*height, x - 0.5*width, y + 0.5*height, x - 1.5*width, y}
gc:setColorRGB(0,0,255)
gc:fillPolygon(leftArrow)
gc:setColorRGB(color.black)
gc:drawPolyLine(leftArrow)
if self.selected and hubStrOn:find("LEFT") then
gc:setPen("medium", "smooth")else
gc:setPen("thin", "smooth")end
local rightArrow = {x + 1.5*width, y, x + 0.5*width, y - 0.5*height, x + 0.5*width, y + 0.5*height, x + 1.5*width, y}
gc:setColorRGB(0,0,255)
gc:fillPolygon(rightArrow)
gc:setColorRGB(color.black)
gc:drawPolyLine(rightArrow)
if self.selected and hubStrOn:find("FORWARD") then
gc:setPen("medium", "smooth")else
gc:setPen("thin", "smooth")end
local downArrow = {x - 0.5*width, y + 0.5*height, x, y + 1.5*height, x + 0.5*width, y + 0.5*height, x - 0.5*width, y + 0.5*height}
gc:setColorRGB(0,0,255)
gc:fillPolygon(downArrow)
gc:setColorRGB(color.black)
gc:drawPolyLine(downArrow)
if self.selected and not hubStrOn:find("FORWARD") and not hubStrOn:find("BACK") and not hubStrOn:find("RIGHT") and not hubStrOn:find("LEFT") then
gc:setPen("medium", "smooth")else
gc:setPen("thin", "smooth")end
gc:setColorRGB(255, 0, 0)
gc:fillArc(x - 0.5*width, y - 0.5*height, width, width, 0, 360)
gc:setColorRGB(color.black)
gc:drawArc(x - 0.5*width, y - 0.5*height, width, width, 0, 360)
function rc:mouseDown(x, y)
width = self.widthend
if not robotConnected then robotConnect() end
if x > self.x - 1.5*width and x < self.x + 1.5*width and y < self.y + 1.5*width and y > self.y - 1.5*width then
self.selected = trueend
if x < self.x - 0.5*self.width and x > self.x - 1.5*self.width
and y < self.y + 0.5*self.width and y > self.y - 0.5*self.width thenelseif x < self.x + 1.5*self.width and x > self.x + 0.5*self.width
lt(0.5)
and y < self.y + 1.5*self.width and y > self.y - 0.5*self.width thenelseif x < self.x + 0.5*self.width and x > self.x - 0.5*self.width
rt(0.5)
and y < self.y + 1.5*self.width and y > self.y + 0.5*self.width thenelseif x < self.x + 0.5*self.width and x > self.x - 0.5*self.width
bk(1)
and y < self.y - 0.5*self.width and y > self.y - 1.5*self.width thenelse
fd(1)
on.escapeKey()end
screen:invalidate()
function rc:mouseUp(x, y)
robotDisconnect()end
self.selected = false
screen:invalidate()
-- TI Innovator User set up
function on.arrowKey(key)
if key == "down" thenend
bk(runTime)elseif key == "up" then
fd(runTime)elseif key == "left" then
lt(15)else
rt(15)end
screen:invalidate()
function on.help()
help = 1 - helpend
screen:invalidate()
function on.charIn(ch)
if ch == "a" then autoDrive()end
elseif ch == "b" then robotConnect() hubStrOn = "READ BRIGHTNESS" TI_Innovator.Send(hubStrOn) TI_Innovator.Read() timeStr = "Press mouse down to take fresh reading"
elseif ch == "c" then robotConnect() hubStrOn = "READ RV.COLORINPUT" TI_Innovator.Send(hubStrOn) TI_Innovator.Read() hubStrOff = '' timeStr = "Press mouse down to take fresh reading"
elseif ch == "d" then robotDisconnect()
elseif ch == "p" then robotConnect() polysides = var.recall("polysides") or 5 polylength = var.recall("polylength") or 20 poly(polysides, polylength)
elseif ch == "r" then robotConnect() hubStrOn = "READ RV.RANGER" TI_Innovator.Send(hubStrOn) TI_Innovator.Read() hubStrOff = '' timeStr = "Press mouse down to take fresh reading"
elseif ch == "s" then robotConnect() hubStrOn = "READ RV SWITCH" TI_Innovator.Send(hubStrOn) TI_Innovator.Read() hubStrOff = '' timeStr = "Press mouse down to take fresh reading"
elseif ch == "w" then wait(runTime)
elseif ch == "?" then help = 1 - help
end
screen:invalidate()
function on.escapeKey()
TI_Innovator.Send(hubStrOff)end
robotDisconnect()
on.resize()
screen:invalidate()
function on.enterKey()
robotConnect()end
screen:invalidate()
function on.mouseDown(x, y)
if robotControls.visible and robotControls:contains(x, y) thenend
robotControls:mouseDown(x, y)else
TI_Innovator.Send(hubStrOn)end
addMsg(hubStrOn)
if hubStrOn:find("READ") then TI_Innovator.Read() end
screen:invalidate()
function on.mouseUp (x,y)
if robotControls.visible and robotControls:contains(x, y) thenend
robotControls:mouseUp(x, y)else
timeStr = ''end
help = 0
TI_Innovator.Send(hubStrOff)
addMsg(hubStrOff)
screen:invalidate()
screen:invalidate()
function str2list(input, def)
local list = {}end
if input:find(def) then
list = input:split(def)else
table.foreachi(list,print)
list = {input}end
return list
function TI_InnovatorReadCallback(port, error_msg) -- this is the callback function that is defined above and catches the result of a READ command send to the Hub.
rxValue = port:getValue() or '' -- this gets the actual return value from the hub and puts it in the variable rxValue. The user may choose any variable name and also may do any calibration or ranging of the value here.end
if tonumber(rxValue) then
rxValue = math.floor(100*rxValue+0.5)/100end
dataList[#dataList+1] = tonumber(rxValue)
index[#index+1]=#dataList
var.store("index", index)
var.store("dataList", dataList)
TI_Innovator.Send("SET SOUND "..100*tonumber(rxValue).." 0.1")
if hubStrOn:find("COLOR") then addMsg(colornames[rxValue]) end
else rxValue = tostring(rxValue)
local list = str2list(rxValue,string.char(10))
if list and #list > 0 then
for k = 1, #list doend
if tonumber(list[k]) thenend
rxValue = tonumber(list[k])
TI_Innovator.Send("SET SOUND "..100*tonumber(rxValue).." 0.1")
break end
if hubStrOn:find("RV SWITCH") then
if tonumber(rxValue) and tonumber(rxValue) == 1 thenend
robotConnected = trueelse
addMsg("ROBOT connected")
hubStrOn = ""
robotConnected = falseend
addMsg("ROBOT not connected")
screen:invalidate()
function TI_InnovatorStateCallback(event)
endaddMsg("TI_InnovatorStateCallback")
if 'ready' == event then
TI_InnovatorConfig()
elseif "disconnected" == event then
-- user may choose to do some clean up or display a msg when the Hub is disconnected.
addMsg("TI_Innovator Hub disconnected")
end
screen:invalidate()
function TI_InnovatorConfig() -- this function is called from TI_InnovatorStateCallback() when a ready connection is succesful.
-- place CONNECT and other Hub startup commands hereend
addMsg("TI_Innovator Hub connected")
on.resize()
TI_Innovator.Send(hubStrOff)
TI_Innovator.Send("BEGIN\n")
screen:invalidate()
function wait(input)
endif input then delay = input end
time_step = 0.1
if delay >= 0 then
timeStr = "Wait Time: "..delay.." seconds"else
delay = math.floor((1/time_step)*(delay - time_step)+0.5)*time_step
TI_Innovator.Send(hubStrOn)
if hubStrOn:find("READ") then TI_Innovator.Read() end
oneShotTimer(1000*time_step,wait)
TI_Innovator.Send(hubStrOff)end
delay = 0
screen:invalidate()
function blink(rep,waitValue)
endlocal lightState = "OFF"
if waitValue then delay = waitValue end
if rep then repeats = rep end
if repeats > 0 then
timeStr = "blink("..(math.floor(repeats+0.5))..", "..delay..")"end
if math.floor(repeats) == repeats then lightState = "ON" else lightState = "OFF" end
TI_Innovator.Send("SET LIGHT "..lightState)
oneShotTimer(1000*delay,blink)
repeats = repeats - 0.5
screen:invalidate()
function alarm(rep,waitValue)
local tone = 220end
if waitValue then delay = waitValue end
if rep then repeats = rep end
if repeats > 0 then
timeStr = "alarm("..(math.floor(repeats+0.5))..", "..delay..")"end
if math.floor(repeats) == repeats then tone = 440 else tone = 220 end
TI_Innovator.Send("SET SOUND "..tone)
oneShotTimer(1000*delay,alarm)
repeats = repeats - 0.5
screen:invalidate()
function waitTone()
if not list1 then list1 = var.recall("list1") endend
if not list2 then list2 = var.recall("list2") end
if list1 and #list1 > 0 and list2 and #list2 > 0 then
if I <= #list1 and list1[I] and list2[I] then -- don't go past the lenght of the arrayend
if list1[I] and list2[I] thenelse
local str = "SET SOUND "..list1[I]*2^(key/12).." TIME "..math.floor(100/(list2[I])+0.5)/100end
hubStrOn = str
TI_Innovator.Send(str)
var.store("hubstr", hubStrOn) addMsg(hubStrOn) oneShotTimer((tempo/list2[I])+20, waitTone)
I = I + 1
hubStrOn = ""end
hubStrOff = ""
addMsg(hubStrOff)
screen:invalidate()
function playTone(list1, list2)
waitTone()end
screen:invalidate()
-- Robot Functions
function fd(input)
if not robotConnected then robotConnect() endend
addMsg("Rover FORWARD "..input)
TI_Innovator.Send('SET RV FORWARD '..input)
screen:invalidate()
function bk(input)
if not robotConnected then robotConnect() endend
addMsg("Rover BACKWARD "..input)
TI_Innovator.Send('SET RV BACKWARD '..input)
screen:invalidate()
function lt(input)
if not robotConnected then robotConnect() endend
addMsg("Rover LEFT "..input.." DEGREES")
TI_Innovator.Send('SET RV LEFT '..input..' DEGREES')
screen:invalidate()
function rt(input)
if not robotConnected then robotConnect() endend
addMsg("Rover RIGHT "..input.." DEGREES")
TI_Innovator.Send('SET RV RIGHT '..input..' DEGREES')
screen:invalidate()
function autoDrive()
if not robotConnected then robotConnect() endend
TI_Innovator.Send("READ RV.RANGER ")
TI_Innovator.Read()
if tonumber(rxValue) and tonumber(rxValue) > 0.1 then
if tonumber(rxValue) > 0.3 thenelse
TI_Innovator.Send('SET RV FORWARD '..time_step)else
addMsg("ROBOT FORWARD")
TI_Innovator.Send('SET RV BACKWARD '..time_step)end
addMsg("ROBOT BACK" )
TI_Innovator.Send('SET RV RIGHT 30 DEGREES')
addMsg("ROBOT RIGHT")
oneShotTimer(1000*time_step,autoDrive)
TI_Innovator.Send('SET RV STOP')end
screen:invalidate()
function poly(sides, length)
if not robotConnected then robotConnect() endend
if sides then delay = sides num = sides end
if length then sl = length end
secs = sl/(0.2*100)
angle = 360/num
addMsg("POLYGON: angle "..angle.." time "..secs.." seconds")
if delay > 0 then
addMsg('SET RV FORWARD '..secs)else
addMsg('SET RV LEFT '..angle..' DEGREES')
TI_Innovator.Send('SET RV FORWARD '..secs)
TI_Innovator.Send('SET RV LEFT '..angle..' DEGREES')
delay = delay - 1
oneShotTimer(1000*2*secs,poly)
addMsg('SET RV LEFT '..angle..' DEGREES')end
TI_Innovator.Send('SET RV LEFT '..angle..' DEGREES')
TI_Innovator.Send('SET RV STOP')
delay = 0
rxValue = delay
screen:invalidate()
--End of user code do not modify below this line
-- TI Innovator Code Do not modify any code below this line
-- oneShotTimer BEGINS
local timerstart = timer.start
local timerstop = timer.stop
timer.start = nil
timer.stop = nil
local currentTimer = nillocal function timerStart(t)
endcurrentTimer = t
timerstart(t.period/1000)
local function timerStop()
endcurrentTimer = nil
timerstop()
local function setTimer(t)
endif t.period==nil or type(t.period)~='number' or t.period < 10 then error('period in milliseconds >= 10') end
timerStart(t)
return t
function oneShotTimer(period, listenerHandler, ...)
endif type(listenerHandler) ~= 'function' then
error('createTimerOneShot: function expected')end
setTimer {
period = period,}
oneShot = true,
listenerHandler = listenerHandler,
params = { ... },
function on.timer()
endlocal ct = currentTimer
if currentTimer == nil then
timerStop()end
if currentTimer.oneShot then
currentTimer = nilend
timerStop()
ct.listenerHandler(unpack(ct.params))
screen:invalidate()
-- oneShotTimer ENDS
-- TI Innovator BEGINS
TI_Innovator = { }
function TI_Innovator.init(theStateCallback)
endif not pcall(function() require 'asi' end) then
addMsg('Hub NOT available')end
return
addMsg('Hub available')
isASIavailable = true
local HANDSHAKE_GREETING = 'ISTI\n'
local HANDSHAKE_ANSWER = 'TISTEM'
local portFoundList = { }
local state
local handshakeState
local notifyEvent
local asiStateListener
local startScanning
local stopScanning
local portFoundListener
local portStateListener
local handshake_SendListener
local handshake_readListener
local handshake_port
local TI_Innovator_port
local baudRate = asi.BAUD_RATE_DEFAULT
local readTimeout = asi.READ_TIMEOUT_DEFAULT-- User callbacks
local stateCallback = theStateCallback
local SendCallback
local readCallbackfunction notifyEvent(event)
addMsg('notifying '.. event)end
if stateCallback then
stateCallback(event)else
addMsg('no callback registered')end
function startScanning()
if isASIavailable thenend
asi.startScanning(portFoundListener)end
notifyEvent('scanning')
function stopScanning()
handshake_port = nilend
portFoundList = { }
asi.stopScanning()
function asiStateListener(asiState)
if asi.ON == asiState thenend
if state == 'active' thenelseif asi.UNSUPPORTED == asiState then
startScanning()end
notifyEvent(asi.UNSUPPORTED)end
function portFoundListener(portFound)
table.insert(portFoundList, portFound)end
if not TI_Innovator_port and not handshake_port then
handshake_port = portFoundList[1]end
oneShotTimer(100, handshake_port.connect, handshake_port, portStateListener)
function portStateListener(reportedPort, event, error_msg)
if asi.CONNECTED == event thenend
-- configure port for handshakeelseif asi.CONNECTING_FAILED == event then
reportedPort:setWriteListener(handshake_writeListener)
reportedPort:setReadListener(handshake_readListener)
reportedPort:setReadTimeout(500)
handshakeState = 'handshake'
-- write handshake greeting
oneShotTimer(200, reportedPort.write, reportedPort, HANDSHAKE_GREETING)
if reportedPort == handshake_port thenelseif asi.DISCONNECTED == event then
table.remove(portFoundList, 1)elseif reportedPort == TI_Innovator_port then
if #portFoundList>0 then
handshake_port = portFoundList[1]else
handshake_port:connect(portStateListener)
handshake_port = nilend
TI_Innovator_port = nilend
asi.startScanning(portFoundListener)
if reportedPort == TI_Innovator_port thenend
if state == 'active' thenend
if reportedPort:getState() == asi.DISCONNECTED thennotifyEvent('disconnected')
reportedPort:connect(portStateListener)else
TI_Innovator_port = nilend
asi.startScanning(portFoundListener)
function handshake_writeListener(reportedPort, error_msg)
if error_msg thenend
returnend
if 'handshake' == handshakeState then
reportedPort:read(#HANDSHAKE_ANSWER+2)end
function handshake_readListener(reportedPort, error_msg)
if error_msg thenend
returnend
local answer = reportedPort:getValue()
if 'handshake' == handshakeState then
-- Validate answerelseif 'ready' == handshakeState then
if answer and answer:find(HANDSHAKE_ANSWER) then
stopScanning()else
handshakeState = 'ready'
reportedPort:write('BEGIN\n')
reportedPort:read(7)
reportedPort:disconnect()end
table.remove(portFoundList, 1)
if #portFoundList>0 then
handshake_port = portFoundList[1]else
handshake_port:connect(portStateListener)
handshake_port = nilend
if answer and answer:find('READY') thenend
-- Configure port for normal useend
TI_Innovator_port = reportedPort
TI_Innovator_port:setReadTimeout(readTimeout)
TI_Innovator.setWriteListener(SendCallback)
TI_Innovator.setReadListener(readCallback)
-- Notify launchpad is ready
notifyEvent('ready')
-- INTERFACE -- BEGINS --
function TI_Innovator.connect()
state = 'active'end
startScanning()
function TI_Innovator.disconnect()
state = 'inactive'end
if isASIavailable then
if TI_Innovator_port thenend
TI_Innovator_port:disconnect()end
TI_Innovator_port = nil
stopScanning()
function TI_Innovator.setWriteListener(newWriteCallback)
writeCallback = newWriteCallbackend
if TI_Innovator_port then
TI_Innovator_port:setWriteListener(writeCallback)end
function TI_Innovator.setReadListener(newReadCallback, newReadObject)
readCallback = newReadCallbackend
if TI_Innovator_port then
TI_Innovator_port:setReadListener(readCallback)end
function TI_Innovator.setBaudRate(newBaudRate)
baudRate = newBaudRateend
if TI_Innovator_port then
TI_Innovator_port:setBaudRate(baudRate)end
function TI_Innovator.setReadTimeout(newReadTimeout)
readTimeout = newReadTimeoutend
if TI_Innovator_port then
TI_Innovator_port:setReadTimeout(readTimeout)end
function TI_Innovator.Send(data)
if not TI_Innovator_port thenend
addMsg('No Hub attached')end
return 'No Hub attached'
local result = TI_Innovator_port:write(data .. '\n')
if result then addMsg(tostring(data)..': '.. tostring(result)) end
return result
function TI_Innovator.Read(bytes_to_read)
if not TI_Innovator_port thenend
return "No TI Hub attached"end
return TI_Innovator_port:read(bytes_to_read)
function TI_Innovator.request(request)
if not TI_Innovator_port thenend
return "No TI Hub attached"end
local result = TI_Innovator_port:write(request .. '\n')
if result then addMsg(tostring(request) .. ': '.. tostring(result))
else addMsg(tostring(request)) end
result = TI_Innovator_port:read()
addMsg('read() '.. tostring(result))
if result then
addMsg('Error sending request: ' .. tostring(request))end
return result
function TI_Innovator.isConnected()
if not TI_Innovator_port thenend
return falseend
return TI_Innovator_port:getState() == asi.CONNECTED
function TI_Innovator.getName()
if not TI_Innovator_port thenend
return "No TI Hub attached"end
return TI_Innovator_port:getName()
function TI_Innovator.getIdentifier()
if not TI_Innovator_port thenend
return "No TI Hub attached"end
return TI_Innovator_port:getIdentifier()
-- INTERFACE -- ENDS --
-- Wait for the ASI to be up and running
asi.addStateListener(asiStateListener)
end
------------------------------------------------------------------------
notes_aliens = {392,440,349,175,261}
times_aliens = {1,1,1,1,1}
notes_bgame = {262,523,440,392,330,392,294,262,523,440,392,330,392,415,440,415,440,330,349,392,440,349,294,440,440,440,494,523,587,494,440,392,349,294,262,523,440,392,330,392,294,262,294,330,349,392,440,440,494,523,523,523,494,440,392,370,392,440,494,523}
times_bgame = {2,4,4,4,4,1.333333333,1.333333333,2,4,4,4,4,1,4,4,4,4,4,4,4,2,4,1.333333333,2,4,4,4,4,4,4,4,4,4,4,2,4,4,4,4,1.333333333,1.333333333,2,4,4,4,4,1,4,4,1.333333333,1.333333333,4,4,4,4,4,4,1.333333333,1.333333333,1}
notes_bday = {260,262,294,262,349,330,260,262,294,262,392,349,260,262,523,440,349,348,330,294,466,465,440,349,392,349}
times_bday = {4,4,2,2,2,1,4,4,2,2,2,1,4,4,2,2,4,4,2,1,4,4,2,2,2,1}
notes_brain = {440,466,523,440,349,392,440,349,0,392,440,349,294,330,349,294,0,294,262,261,262,261,262,0,349,330,294,294,587,523,466,440,392,349,330,331,660,587,523,466,440,392,349,348,349,348,349}
times_brain = {16,48,16,48,16,48,24,16,48,24,16,48,16,48,24,16,48,24,16,48,16,48,6,1.5,16,48,16,48,16,48,16,48,16,48,16,48,16,48,16,48,16,48,16,48,16,48,6}
notes_elise = {330,660,622,660,622,660,494,587,523,440,262,330,440,494,330,415,494,523,330,660,622,660,622,660,494,587,523,440,262,330,440,494,262,523,494,440,440}
times_elise = {4,4,4,4,4,4,4,4,4,1,4,4,4,1,4,4,4,1,4,4,4,4,4,4,4,4,4,1,4,4,4,1,4,4,4,1,1}
notes_home = {262,294,330,349,440,392,330,392,349,330,349,294,262,262}
times_home = {4,4,2,4,4,2,4,4,4,4,4,4,1,1}
notes_harmonic = {440.,495,550.,586.67,660.,733.33,806.67,880.}
notes_welltemp = {440.,493.883,554.365,587.33,659.255,739.99,830.61,880.}
times_scale = {2,2,2,2,2,2,2,2}
-- TI Innovator Init Values
platform.apilevel = '2.7'
local screen = platform.window
local date = "180318"require 'color'
pcall(function() require 'asi' end)local hubStrOn, hubStrOff, msgStr, rxValue, timeStr, repeats, time_step, delay
local list1, list2, index, dataList = {}, {}, {}, {}
var.store("index", index)
var.store("dataList", dataList)
local oldChar = ''
local help = 1
local fontSize = 20local robotConnected = false
local time_step = var.recall("time_step") or 0.5
local runTime = var.recall("runtime") or 10
local runtimeStr = "Run Time: "..runTime
local robotSpeed = var.recall("speed") or 10
local speedStr = "Robot Speed: "..robotSpeed.." cm/s"
local colornames = {"red","green","blue","cyan","magenta","yellow","black","white","gray"}var.monitor("speed")
var.monitor("runtime")
var.monitor("time_step")
var.monitor("hubstr")
var.monitor("polysides")
var.monitor("polylength")function on.varChange(varList)
robotSpeed = var.recall("speed") or 10end
speedStr = "Robot Speed: "..robotSpeed.." cm/s"
runTime = var.recall("runtime") or 10
runtimeStr = "Run Time: "..runTime
time_step = var.recall("time_step") or 0.5
local colornames = {"red","green","blue","cyan","magenta","yellow","black","white","gray"}
polysides = var.recall("polysides") or 5
polylength = var.recall("polylength") or 20
hubStrOn = string.upper(var.recall("hubstr")) or ''
if hubStrOn:find("ON") then
hubStrOff = hubStrOn:gsub("ON","OFF")else
TI_Innovator.Send(hubStrOn)
addMsg(hubStrOn)
hubStrOff = ''end
TI_Innovator.Send(hubStrOn)
addMsg(hubStrOn)
if hubStrOn:find("READ") then TI_Innovator.Read() end
screen:invalidate()
function addMsg(input)
msgStr = input
print(msgStr)
screen:invalidate()end
function on.construction()
end--the next three lines are required for Hub connection
TI_Innovator.init(TI_InnovatorStateCallback)
TI_Innovator.setReadListener(TI_InnovatorReadCallback)
TI_Innovator.connect()Menu={
{"About",}
{" ©2018 Compass Learning Technologies", function() end},},
{" Version "..date, function() end},
{" Contact: steve@compasstech.com.au ", function() end},
{" Help?", function() on.help() end},
{"Controls",
{"Scan and Connect", function() TI_Innovator.connect() end},},
{"Disconnect", function() TI_Innovator.disconnect() on.resize() end},
{"RESET", function() on.resize() end},
{"SET Samples",
{"SET LIGHT ON/OFF (default)", function() hubStrOn = "SET LIGHT ON" hubStrOff = "SET LIGHT OFF" TI_Innovator.Send(hubStrOn) addMsg(hubStrOn) rxValue = "Press mouse down to toggle light" end},
{"SET COLOR.RED ON/OFF", function() hubStrOn = "SET COLOR.RED ON" hubStrOff = "SET COLOR.RED OFF" TI_Innovator.Send(hubStrOn) addMsg(hubStrOn) rxValue = "Press mouse down to toggle red LED" end},
{"SET COLOR.GREEN ON/OFF", function() hubStrOn = "SET COLOR.GREEN ON" hubStrOff = "SET COLOR.GREEN OFF" TI_Innovator.Send(hubStrOn) addMsg(hubStrOn) rxValue = "Press mouse down to toggle green LED" end},
{"SET COLOR.BLUE ON/OFF", function() hubStrOn = "SET COLOR.BLUE ON" hubStrOff = "SET COLOR.BLUE OFF" TI_Innovator.Send(hubStrOn) addMsg(hubStrOn) rxValue = "Press mouse down to toggle blue LED" end},
{"SET SOUND 220 1", function() hubStrOn = "SET SOUND 220 1" hubStrOff = "SET SOUND 0 1" TI_Innovator.Send(hubStrOn) addMsg(hubStrOn) rxValue = "Press mouse down to repeat sound" end},
{'_________________', function() end},
{"SET SPEAKER 1 220 5", function() hubStrOn = "SET SPEAKER 1 220 5" TI_Innovator.Send("CONNECT SPEAKER 1 OUT1") TI_Innovator.Send(hubStrOn) hubStrOff = "SET SPEAKER 1 0 1" rxValue = "Press mouse down to toggle speaker" end},
{"SET LED 1 ON", function() hubStrOn = "SET LED 1 ON" TI_Innovator.Send("CONNECT LED 1 OUT1") TI_Innovator.Send(hubStrOn) hubStrOff = "SET LED 1 0FF" rxValue = "Press mouse down to toggle LED" end},
{"SET SERVO 1 CW 50 5 (OUT3)", function() TI_Innovator.Send("CONNECT SERVO 1 OUT3") hubStrOn = "SET SERVO 1 CW 50 5" hubStrOff = "SET SERVO 1 CW 50 0" rxValue = "Press mouse down to toggle servo" end},
{"SET ANALOG.OUT 1 100", function() hubStrOn = "SET ANALOG.OUT 1 100" TI_Innovator.Send("CONNECT ANALOG.OUT 1 OUT1") TI_Innovator.Send(hubStrOn) hubStrOff = "SET ANALOG.OUT 1 0" rxValue = "Press mouse down to toggle analog read" end},
{"SET DIGITAL.OUT 1 ON", function() hubStrOn = "SET DIGITAL.OUT 1 ON" TI_Innovator.Send("CONNECT DIGITAL.OUT 1 OUT1") TI_Innovator.Send(hubStrOn) hubStrOff = "SET DIGITAL.OUT 1 0FF" rxValue = "Press mouse down to toggle digital read" end},
},
{"READ Samples",
{"READ BRIGHTNESS", function() hubStrOn = "READ BRIGHTNESS" TI_Innovator.Send(hubStrOn) TI_Innovator.Read() timeStr = "Press mouse down to take fresh reading" end},},
{'_________________', function() end},
{"READ RV SWITCH", function() hubStrOn = "READ RV SWITCH" TI_Innovator.Send(hubStrOn) TI_Innovator.Read() hubStrOff = '' timeStr = "Press mouse down to take fresh reading" end},
{"READ RV.RANGER (r)", function() robotConnect() hubStrOn = "READ RV.RANGER" TI_Innovator.Send(hubStrOn) TI_Innovator.Read() hubStrOff = '' timeStr = "Press mouse down to take fresh reading" end},
{"READ RV.COLORINPUT (c)", function() robotConnect() hubStrOn = "READ RV.COLORINPUT" TI_Innovator.Send(hubStrOn) TI_Innovator.Read() hubStrOff = '' timeStr = "Press mouse down to take fresh reading" end},
{'_________________', function() end},
{"READ RANGER 1", function() hubStrOn = "READ RANGER 1" TI_Innovator.Send("CONNECT RANGER 1 IN1") math.eval("wait(0.5)") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() hubStrOff = '' timeStr = "Press mouse down to take fresh reading" end},
{"READ ANALOG.IN 1", function() hubStrOn = "READ ANALOG.IN 1" TI_Innovator.Send("CONNECT ANALOG.IN 1 IN1") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() hubStrOff = '' timeStr = "Press mouse down to take fresh reading" driver = "ANALOG.IN 1" driverConnected = true end},
{"READ DIGITAL.IN 1", function() hubStrOn = "READ DIGITAL.IN 1" TI_Innovator.Send("CONNECT DIGITAL.IN 1 IN1") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() hubStrOff = '' timeStr = "Press mouse down to take fresh reading" driver = "DIGITAL.IN 1" driverConnected = true end},
{"Sound Samples",
{"C4", function() hubStrOn = "SET SOUND 262 TIME 1" TI_Innovator.Send(hubStrOn) hubStrOff = "SET SOUND 0 1" msgStr = hubStrOff rxValue = "Press mouse down to play sound" end},},
{"A4", function() hubStrOn = "SET SOUND 440 TIME 1" TI_Innovator.Send(hubStrOn) hubStrOff = "SET SOUND 0 1" msgStr = hubStrOff rxValue = "Press mouse down to play sound" end},
{"C5", function() hubStrOn = "SET SOUND 523 TIME 1" TI_Innovator.Send(hubStrOn) hubStrOff = "SET SOUND 0 1" msgStr = hubStrOff rxValue = "Press mouse down to play sound" end},
{"No tone", function() hubStrOn = "SET SOUND 0 TIME 1" TI_Innovator.Send(hubStrOn) hubStrOff = "SET SOUND 0 1" msgStr = hubStrOff end},
{"Aliens (sample)", function() tempo = 1000 I=1 list1 = notes_aliens list2 = times_aliens playTone(list1,list2) rxValue = "Aliens" end},
{"BallGame (sample)", function() tempo = 1000 I=1 list1 = notes_bgame list2 = times_bgame playTone(list1,list2) rxValue = "Take me out to the Ball Game" end},
{"Happy Birthday (sample)", function() tempo = 1000 I=1 list1 = notes_bday list2 = times_bday playTone(list1,list2) rxValue = "Happy Birthday" end}, {"If I Only Had a Brain (sample)", function() tempo = 4000 I=1 list1 = notes_brain list2 = times_brain playTone(list1,list2) rxValue = "If I only had a brain" end},
{"Fur Elise (sample)", function() tempo = 1000 I=1 list1 = notes_elise list2 = times_elise playTone(list1,list2) rxValue = "Fur Elise" end},
{"Home on the Range (sample)", function() tempo = 1000 I=1 list1 = notes_home list2 = times_home playTone(list1,list2) rxValue = "Home on the Range" end},
{"Well-tempered Scale", function() tempo = 1000 I=1 list1 = notes_welltemp list2 = times_scale playTone(list1,list2) rxValue = "Well tempered scale" end},
{"Harmonic Scale", function() tempo = 1000 I=1 list1 = notes_harmonic list2 = times_scale playTone(list1,list2) rxValue = "Harmonic scale" end},
{"Robot Samples",
{"CONNECT RV (enter)", function() robotConnect() end},},
{"DISCONNECT RV (d)", function() robotDisconnect() end},
{"READ RV SWITCH", function() hubStrOn = "READ RV SWITCH" TI_Innovator.Send(hubStrOn) TI_Innovator.Read() hubStrOff = '' timeStr = "Press mouse down to take fresh reading" end},
{"ROBOT FD runTime", function() fd(runTime) end},
{"ROBOT BK runTime", function() bk(runTime) end},
{"ROBOT LT 0.5 secs", function() lt(45) end},
{"ROBOT RT 0.5 secs", function() rt(45) end},
{"autoDrive - (a)", function() autoDrive() end},
{"poly(polysides,polylength) - (p)", function() polysides = var.recall("polysides") or 5 polylength = var.recall("polylength") or 20 poly(polysides, polylength) end},
{"TIMER Samples",
{"wait(runTime) (w)", function() wait(runTime) end},},
{"blink(runTime,1)", function() blink(runTime,1) end},
{"alarm(runTime,0.5)", function() alarm(runTime,0.5) end},
toolpalette.register(Menu)
screen:invalidate()
-- Layout Functions
function on.resize(width, height)
w = screen:width()end
h = screen:height()
hubStrOn, hubStrOff, msgStr, rxValue, timeStr = "", "", "", "", ""
var.store("hubstr", hubStrOn)
delay, num, sl, repeats, oldChar = 0, 0, 0, 0, 0.1, 1, ""
tempo, key, I = 1000, 0, 1 time_step = var.recall("time_step") or 0.5
robotSpeed = var.recall("speed") or 10
speedStr = "Robot Speed: "..robotSpeed.." cm/s"
runTime = var.recall("runtime") or 10
fontSize = math.floor(h/20 + 0.5)
if hh then
fontSize = fontSize > 7 and fontSize or 7end
fontSize = fontSize < 24 and fontSize or 24
fontSize1 = math.floor(h/30 + 0.5)
if hh then
fontSize = fontSize > 7 and fontSize or 7end
fontSize = fontSize < 24 and fontSize or 24
list1, list2, index, dataList = {}, {}, {}, {}
var.store("index", index)
var.store("dataList", dataList)
robotControls = rc(0.5*w, 0.5*h, 0.15*h, false, true)
if TI_Innovator.isConnected() then
addMsg("TI Innovator Hub ready")end
function on.paint (gc)
gc:setFont("sansserif", "r", fontSize)end
if TI_Innovator.isConnected() then gc:setColorRGB(0,255,0) else gc:setColorRGB(255,0,0) end
if TI_Innovator.isConnected() then
gc:fillRect (0, 0, w, 0.025*h)else
local sw = gc:getStringWidth(runtimeStr)
gc:drawString(runtimeStr, 0.9*w - sw, 0.1*h, "middle")
local sw = gc:getStringWidth(speedStr)
gc:drawString(speedStr, 0.965*w - sw, 0.2*h, "middle")
robotControls:paint(gc)
gc:fillRect (0, 0, w, 0.025*h)end
gc:drawString("Wait for connection, then", 0.025*w, 0.1*h, "middle")
gc:drawString("press anywhere to activate Hub", 0.025*w, 0.2*h, "middle")
gc:setFont("sansserif", "r", fontSize1)
gc:drawString("Change settings (speed,runTime,polysides,polylength) or enter ", 0.025*w, 0.3*h, "middle")
gc:drawString("new hub commands (hubStr) using the spreadsheet on the next page", 0.025*w, 0.35*h, "middle")
gc:drawString("Press 'a' for AUTODRIVE ", 0.025*w, 0.45*h, "middle")
gc:drawString("Press 'b' to read BRIGHTNESS ", 0.025*w, 0.5*h, "middle")
gc:drawString("Press 'c' to read RV.COLORINPUT ", 0.025*w, 0.55*h, "middle")
gc:drawString("Press 'p' for Polygon ", 0.025*w, 0.6*h, "middle")
gc:drawString("Press 'r' to READ RV.RANGER ", 0.025*w, 0.65*h, "middle")
gc:drawString("Press 's' to READ RV.SWITCH ", 0.025*w, 0.7*h, "middle")
gc:drawString("Press 'w' to wait ", 0.025*w, 0.75*h, "middle")
gc:drawString("Press 'enter' to CONNECT RV ", 0.025*w, 0.8*h, "middle")
gc:drawString("Press 'd' to DISCONNECT ", 0.025*w, 0.85*h, "middle")
if TI_Innovator.isConnected() then gc:setColorRGB(0,255,0) else gc:setColorRGB(255,0,0) end
gc:setFont("sansserif", "r", fontSize)
gc:drawString(timeStr, 0.025*w, 0.8*h, "middle")
gc:drawString(msgStr, 0.025*w, 0.875*h, "middle")
gc:drawString(rxValue, 0.025*w, 0.95*h, "middle")
gc:setFont("sansserif", "r", fontSize1)
gc:setColorRGB(0, 0, 255)
local str = "TI Innovator Rover Disconnected"
if TI_Innovator.isConnected() and robotConnected then str = "Rover connected" end
local sw = gc:getStringWidth(str)
gc:drawString(str, 0.975*w - sw, 0.95*h, "middle")
rc = class()
function robotConnect()
pcall(function()end
TI_Innovator.Send('BEGIN\n')end)
robotControls.visible = true
TI_Innovator.Send("CONNECT RV")
hubStrOn = "READ RV SWITCH"
var.store("hubstr", hubStrOn)
wait(0.5)
TI_Innovator.Send(hubStrOn)
TI_Innovator.Read()
screen:invalidate()
function robotDisconnect()
pcall(function()end
TI_Innovator.Send('BEGIN')end)
robotConnected = false
hubStrOn = 'DISCONNECT RV'
hubStrOff = ''
delay = 0
runTime = var.recall("runtime") or 10
var.store("hubstr", hubStrOn)
screen:invalidate()
function rc:init(x, y, width, selected, visible)
self.x = xend
self.y = y
self.width = width
self.height = width
self.visible = visible
self.selected = selected
function rc:contains(x, y)
local sw = self.width or self.heightend
local sh = self.height or self.width
return x >= self.x - 1.5*sw and x <= self.x + 1.5*sw and
y >= self.y - 1.5*sh and y <= self.y + 1.5*sh
function rc:paint(gc)
w = screen:width()end
h = screen:height()
if self.visible == true then
local x = self.xend
local y = self.y
local width = self.width
local height = self.width
gc:setPen("thin", "smooth")
if self.selected and hubStrOn:find("BACK") then
gc:setPen("medium", "smooth")else
gc:setPen("thin", "smooth")end
local upArrow = {x - 0.5*width, y - 0.5*height, x, y - 1.5*height, x + 0.5*width, y - 0.5*height, x - 0.5*width, y - 0.5*height}
gc:setColorRGB(0,0,255)
gc:fillPolygon(upArrow)
gc:setColorRGB(color.black)
gc:drawPolyLine(upArrow)
if self.selected and hubStrOn:find("RIGHT") then
gc:setPen("medium", "smooth")else
gc:setPen("thin", "smooth")end
local leftArrow = {x - 1.5*width, y, x - 0.5*width, y - 0.5*height, x - 0.5*width, y + 0.5*height, x - 1.5*width, y}
gc:setColorRGB(0,0,255)
gc:fillPolygon(leftArrow)
gc:setColorRGB(color.black)
gc:drawPolyLine(leftArrow)
if self.selected and hubStrOn:find("LEFT") then
gc:setPen("medium", "smooth")else
gc:setPen("thin", "smooth")end
local rightArrow = {x + 1.5*width, y, x + 0.5*width, y - 0.5*height, x + 0.5*width, y + 0.5*height, x + 1.5*width, y}
gc:setColorRGB(0,0,255)
gc:fillPolygon(rightArrow)
gc:setColorRGB(color.black)
gc:drawPolyLine(rightArrow)
if self.selected and hubStrOn:find("FORWARD") then
gc:setPen("medium", "smooth")else
gc:setPen("thin", "smooth")end
local downArrow = {x - 0.5*width, y + 0.5*height, x, y + 1.5*height, x + 0.5*width, y + 0.5*height, x - 0.5*width, y + 0.5*height}
gc:setColorRGB(0,0,255)
gc:fillPolygon(downArrow)
gc:setColorRGB(color.black)
gc:drawPolyLine(downArrow)
if self.selected and not hubStrOn:find("FORWARD") and not hubStrOn:find("BACK") and not hubStrOn:find("RIGHT") and not hubStrOn:find("LEFT") then
gc:setPen("medium", "smooth")else
gc:setPen("thin", "smooth")end
gc:setColorRGB(255, 0, 0)
gc:fillArc(x - 0.5*width, y - 0.5*height, width, width, 0, 360)
gc:setColorRGB(color.black)
gc:drawArc(x - 0.5*width, y - 0.5*height, width, width, 0, 360)
function rc:mouseDown(x, y)
width = self.widthend
if not robotConnected then robotConnect() end
if x > self.x - 1.5*width and x < self.x + 1.5*width and y < self.y + 1.5*width and y > self.y - 1.5*width then
self.selected = trueend
if x < self.x - 0.5*self.width and x > self.x - 1.5*self.width
and y < self.y + 0.5*self.width and y > self.y - 0.5*self.width thenelseif x < self.x + 1.5*self.width and x > self.x + 0.5*self.width
lt(0.5)
and y < self.y + 1.5*self.width and y > self.y - 0.5*self.width thenelseif x < self.x + 0.5*self.width and x > self.x - 0.5*self.width
rt(0.5)
and y < self.y + 1.5*self.width and y > self.y + 0.5*self.width thenelseif x < self.x + 0.5*self.width and x > self.x - 0.5*self.width
bk(1)
and y < self.y - 0.5*self.width and y > self.y - 1.5*self.width thenelse
fd(1)
on.escapeKey()end
screen:invalidate()
function rc:mouseUp(x, y)
robotDisconnect()end
self.selected = false
screen:invalidate()
-- TI Innovator User set up
function on.arrowKey(key)
if key == "down" thenend
bk(runTime)elseif key == "up" then
fd(runTime)elseif key == "left" then
lt(15)else
rt(15)end
screen:invalidate()
function on.help()
help = 1 - helpend
screen:invalidate()
function on.charIn(ch)
if ch == "a" then autoDrive()end
elseif ch == "b" then robotConnect() hubStrOn = "READ BRIGHTNESS" TI_Innovator.Send(hubStrOn) TI_Innovator.Read() timeStr = "Press mouse down to take fresh reading"
elseif ch == "c" then robotConnect() hubStrOn = "READ RV.COLORINPUT" TI_Innovator.Send(hubStrOn) TI_Innovator.Read() hubStrOff = '' timeStr = "Press mouse down to take fresh reading"
elseif ch == "d" then robotDisconnect()
elseif ch == "p" then robotConnect() polysides = var.recall("polysides") or 5 polylength = var.recall("polylength") or 20 poly(polysides, polylength)
elseif ch == "r" then robotConnect() hubStrOn = "READ RV.RANGER" TI_Innovator.Send(hubStrOn) TI_Innovator.Read() hubStrOff = '' timeStr = "Press mouse down to take fresh reading"
elseif ch == "s" then robotConnect() hubStrOn = "READ RV SWITCH" TI_Innovator.Send(hubStrOn) TI_Innovator.Read() hubStrOff = '' timeStr = "Press mouse down to take fresh reading"
elseif ch == "w" then wait(runTime)
elseif ch == "?" then help = 1 - help
end
screen:invalidate()
function on.escapeKey()
TI_Innovator.Send(hubStrOff)end
robotDisconnect()
on.resize()
screen:invalidate()
function on.enterKey()
robotConnect()end
screen:invalidate()
function on.mouseDown(x, y)
if robotControls.visible and robotControls:contains(x, y) thenend
robotControls:mouseDown(x, y)else
TI_Innovator.Send(hubStrOn)end
addMsg(hubStrOn)
if hubStrOn:find("READ") then TI_Innovator.Read() end
screen:invalidate()
function on.mouseUp (x,y)
if robotControls.visible and robotControls:contains(x, y) thenend
robotControls:mouseUp(x, y)else
timeStr = ''end
help = 0
TI_Innovator.Send(hubStrOff)
addMsg(hubStrOff)
screen:invalidate()
screen:invalidate()
function str2list(input, def)
local list = {}end
if input:find(def) then
list = input:split(def)else
table.foreachi(list,print)
list = {input}end
return list
function TI_InnovatorReadCallback(port, error_msg) -- this is the callback function that is defined above and catches the result of a READ command send to the Hub.
rxValue = port:getValue() or '' -- this gets the actual return value from the hub and puts it in the variable rxValue. The user may choose any variable name and also may do any calibration or ranging of the value here.end
if tonumber(rxValue) then
rxValue = math.floor(100*rxValue+0.5)/100end
dataList[#dataList+1] = tonumber(rxValue)
index[#index+1]=#dataList
var.store("index", index)
var.store("dataList", dataList)
TI_Innovator.Send("SET SOUND "..100*tonumber(rxValue).." 0.1")
if hubStrOn:find("COLOR") then addMsg(colornames[rxValue]) end
else rxValue = tostring(rxValue)
local list = str2list(rxValue,string.char(10))
if list and #list > 0 then
for k = 1, #list doend
if tonumber(list[k]) thenend
rxValue = tonumber(list[k])
TI_Innovator.Send("SET SOUND "..100*tonumber(rxValue).." 0.1")
break end
if hubStrOn:find("RV SWITCH") then
if tonumber(rxValue) and tonumber(rxValue) == 1 thenend
robotConnected = trueelse
addMsg("ROBOT connected")
hubStrOn = ""
robotConnected = falseend
addMsg("ROBOT not connected")
screen:invalidate()
function TI_InnovatorStateCallback(event)
endaddMsg("TI_InnovatorStateCallback")
if 'ready' == event then
TI_InnovatorConfig()
elseif "disconnected" == event then
-- user may choose to do some clean up or display a msg when the Hub is disconnected.
addMsg("TI_Innovator Hub disconnected")
end
screen:invalidate()
function TI_InnovatorConfig() -- this function is called from TI_InnovatorStateCallback() when a ready connection is succesful.
-- place CONNECT and other Hub startup commands hereend
addMsg("TI_Innovator Hub connected")
on.resize()
TI_Innovator.Send(hubStrOff)
TI_Innovator.Send("BEGIN\n")
screen:invalidate()
function wait(input)
endif input then delay = input end
time_step = 0.1
if delay >= 0 then
timeStr = "Wait Time: "..delay.." seconds"else
delay = math.floor((1/time_step)*(delay - time_step)+0.5)*time_step
TI_Innovator.Send(hubStrOn)
if hubStrOn:find("READ") then TI_Innovator.Read() end
oneShotTimer(1000*time_step,wait)
TI_Innovator.Send(hubStrOff)end
delay = 0
screen:invalidate()
function blink(rep,waitValue)
endlocal lightState = "OFF"
if waitValue then delay = waitValue end
if rep then repeats = rep end
if repeats > 0 then
timeStr = "blink("..(math.floor(repeats+0.5))..", "..delay..")"end
if math.floor(repeats) == repeats then lightState = "ON" else lightState = "OFF" end
TI_Innovator.Send("SET LIGHT "..lightState)
oneShotTimer(1000*delay,blink)
repeats = repeats - 0.5
screen:invalidate()
function alarm(rep,waitValue)
local tone = 220end
if waitValue then delay = waitValue end
if rep then repeats = rep end
if repeats > 0 then
timeStr = "alarm("..(math.floor(repeats+0.5))..", "..delay..")"end
if math.floor(repeats) == repeats then tone = 440 else tone = 220 end
TI_Innovator.Send("SET SOUND "..tone)
oneShotTimer(1000*delay,alarm)
repeats = repeats - 0.5
screen:invalidate()
function waitTone()
if not list1 then list1 = var.recall("list1") endend
if not list2 then list2 = var.recall("list2") end
if list1 and #list1 > 0 and list2 and #list2 > 0 then
if I <= #list1 and list1[I] and list2[I] then -- don't go past the lenght of the arrayend
if list1[I] and list2[I] thenelse
local str = "SET SOUND "..list1[I]*2^(key/12).." TIME "..math.floor(100/(list2[I])+0.5)/100end
hubStrOn = str
TI_Innovator.Send(str)
var.store("hubstr", hubStrOn) addMsg(hubStrOn) oneShotTimer((tempo/list2[I])+20, waitTone)
I = I + 1
hubStrOn = ""end
hubStrOff = ""
addMsg(hubStrOff)
screen:invalidate()
function playTone(list1, list2)
waitTone()end
screen:invalidate()
-- ROBOT COMMANDS BEGIN
function fd(input)
if not robotConnected then robotConnect() endend
addMsg("Rover FORWARD "..input)
TI_Innovator.Send('SET RV FORWARD '..input)
screen:invalidate()
function bk(input)
if not robotConnected then robotConnect() endend
addMsg("Rover BACKWARD "..input)
TI_Innovator.Send('SET RV BACKWARD '..input)
screen:invalidate()
function lt(input)
if not robotConnected then robotConnect() endend
addMsg("Rover LEFT "..input.." DEGREES")
TI_Innovator.Send('SET RV LEFT '..input..' DEGREES')
screen:invalidate()
function rt(input)
if not robotConnected then robotConnect() endend
addMsg("Rover RIGHT "..input.." DEGREES")
TI_Innovator.Send('SET RV RIGHT '..input..' DEGREES')
screen:invalidate()
function autoDrive()
if not robotConnected then robotConnect() endend
TI_Innovator.Send("READ RV.RANGER ")
TI_Innovator.Read()
if tonumber(rxValue) and tonumber(rxValue) > 0.1 then
if tonumber(rxValue) > 0.3 thenelse
TI_Innovator.Send('SET RV FORWARD '..time_step)else
addMsg("ROBOT FORWARD")
TI_Innovator.Send('SET RV BACKWARD '..time_step)end
addMsg("ROBOT BACK" )
TI_Innovator.Send('SET RV RIGHT 30 DEGREES')
addMsg("ROBOT RIGHT")
oneShotTimer(1000*time_step,autoDrive)
TI_Innovator.Send('SET RV STOP')end
screen:invalidate()
function poly(sides, length)
if not robotConnected then robotConnect() endend
if sides then delay = sides num = sides end
if length then sl = length end
secs = sl/(0.2*100)
angle = 360/num
addMsg("POLYGON: angle "..angle.." time "..secs.." seconds")
if delay > 0 then
addMsg('SET RV FORWARD '..secs)else
addMsg('SET RV LEFT '..angle..' DEGREES')
TI_Innovator.Send('SET RV FORWARD '..secs)
TI_Innovator.Send('SET RV LEFT '..angle..' DEGREES')
delay = delay - 1
oneShotTimer(1000*2*secs,poly)
addMsg('SET RV LEFT '..angle..' DEGREES')end
TI_Innovator.Send('SET RV LEFT '..angle..' DEGREES')
TI_Innovator.Send('SET RV STOP')
delay = 0
rxValue = delay
screen:invalidate()
-- oneShotTimer BEGINS
local timerstart = timer.start
local timerstop = timer.stop
timer.start = nil
timer.stop = nil
local currentTimer = nillocal function timerStart(t)
endcurrentTimer = t
timerstart(t.period/1000)
local function timerStop()
endcurrentTimer = nil
timerstop()
local function setTimer(t)
endif t.period==nil or type(t.period)~='number' or t.period < 10 then error('period in milliseconds >= 10') end
timerStart(t)
return t
function oneShotTimer(period, listenerHandler, ...)
endif type(listenerHandler) ~= 'function' then
error('createTimerOneShot: function expected')end
setTimer {
period = period,}
oneShot = true,
listenerHandler = listenerHandler,
params = { ... },
function on.timer()
endlocal ct = currentTimer
if currentTimer == nil then
timerStop()end
if currentTimer.oneShot then
currentTimer = nilend
timerStop()
ct.listenerHandler(unpack(ct.params))
screen:invalidate()
-- oneShotTimer ENDS
-- TI Innovator BEGINS
TI_Innovator = { }
function TI_Innovator.init(theStateCallback)
endif not pcall(function() require 'asi' end) then
addMsg('Hub NOT available')end
return
addMsg('Hub available')
isASIavailable = true
local HANDSHAKE_GREETING = 'ISTI\n'
local HANDSHAKE_ANSWER = 'TISTEM'
local portFoundList = { }
local state
local handshakeState
local notifyEvent
local asiStateListener
local startScanning
local stopScanning
local portFoundListener
local portStateListener
local handshake_SendListener
local handshake_readListener
local handshake_port
local TI_Innovator_port
local baudRate = asi.BAUD_RATE_DEFAULT
local readTimeout = asi.READ_TIMEOUT_DEFAULT-- User callbacks
local stateCallback = theStateCallback
local SendCallback
local readCallbackfunction notifyEvent(event)
addMsg('notifying '.. event)end
if stateCallback then
stateCallback(event)else
addMsg('no callback registered')end
function startScanning()
if isASIavailable thenend
asi.startScanning(portFoundListener)end
notifyEvent('scanning')
function stopScanning()
handshake_port = nilend
portFoundList = { }
asi.stopScanning()
function asiStateListener(asiState)
if asi.ON == asiState thenend
if state == 'active' thenelseif asi.UNSUPPORTED == asiState then
startScanning()end
notifyEvent(asi.UNSUPPORTED)end
function portFoundListener(portFound)
addMsg('portFoundListener '.. portFound:getName())end
table.insert(portFoundList, portFound)
if not TI_Innovator_port and not handshake_port then
handshake_port = portFoundList[1]end
oneShotTimer(100, handshake_port.connect, handshake_port, portStateListener)
function portStateListener(reportedPort, event, error_msg)
addMsg('portStateListener '..reportedPort:getName()..' '..event)end
if asi.CONNECTED == event then
-- configure port for handshakeelseif asi.CONNECTING_FAILED == event then
reportedPort:setWriteListener(handshake_writeListener)
reportedPort:setReadListener(handshake_readListener)
reportedPort:setReadTimeout(500)
handshakeState = 'handshake'
-- write handshake greeting
addMsg("HANDSHAKE_GREETING: "..HANDSHAKE_GREETING)
oneShotTimer(200, reportedPort.write, reportedPort, HANDSHAKE_GREETING)
if reportedPort == handshake_port thenelseif asi.DISCONNECTED == event then
table.remove(portFoundList, 1)elseif reportedPort == TI_Innovator_port then
if #portFoundList>0 then
handshake_port = portFoundList[1]else
handshake_port:connect(portStateListener)
handshake_port = nilend
TI_Innovator_port = nilend
asi.startScanning(portFoundListener)
if reportedPort == TI_Innovator_port thenend
if state == 'active' thenend
if reportedPort:getState() == asi.DISCONNECTED thennotifyEvent('disconnected')
reportedPort:connect(portStateListener)else
TI_Innovator_port = nilend
asi.startScanning(portFoundListener)
function handshake_writeListener(reportedPort, error_msg)
if error_msg thenend
addMsg('handshake_writeListener '..error_msg)end
return
if 'handshake' == handshakeState then
reportedPort:read(#HANDSHAKE_ANSWER+2)end
function handshake_readListener(reportedPort, error_msg)
if error_msg thenend
addMsg('handshake_writeListener '..error_msg)end
return
local answer = reportedPort:getValue()
if 'handshake' == handshakeState then
-- Validate answerelseif 'ready' == handshakeState then
if answer and answer:find(HANDSHAKE_ANSWER) then
addMsg("HANDSHAKE_ANSWER: "..HANDSHAKE_ANSWER)else
stopScanning()
handshakeState = 'ready'
reportedPort:write('BEGIN\n')
reportedPort:read(7)
reportedPort:disconnect()end
table.remove(portFoundList, 1)
if #portFoundList>0 then
handshake_port = portFoundList[1]else
handshake_port:connect(portStateListener)
handshake_port = nilend
if answer and answer:find('READY') thenend
-- Configure port for normal useend
TI_Innovator_port = reportedPort
TI_Innovator_port:setReadTimeout(readTimeout)
TI_Innovator.setWriteListener(SendCallback)
TI_Innovator.setReadListener(readCallback)
-- Notify launchpad is ready
notifyEvent('ready')
-- INTERFACE -- BEGINS --
function TI_Innovator.connect()
state = 'active'end
startScanning()
function TI_Innovator.disconnect()
state = 'inactive'end
if isASIavailable then
if TI_Innovator_port thenend
TI_Innovator_port:disconnect()end
TI_Innovator_port = nil
stopScanning()
function TI_Innovator.setWriteListener(newWriteCallback)
writeCallback = newWriteCallbackend
if TI_Innovator_port then
TI_Innovator_port:setWriteListener(writeCallback)end
function TI_Innovator.setReadListener(newReadCallback, newReadObject)
readCallback = newReadCallbackend
if TI_Innovator_port then
TI_Innovator_port:setReadListener(readCallback)end
function TI_Innovator.setBaudRate(newBaudRate)
baudRate = newBaudRateend
if TI_Innovator_port then
TI_Innovator_port:setBaudRate(baudRate)end
function TI_Innovator.setReadTimeout(newReadTimeout)
readTimeout = newReadTimeoutend
if TI_Innovator_port then
TI_Innovator_port:setReadTimeout(readTimeout)end
function TI_Innovator.Send(data)
if not TI_Innovator_port thenend
addMsg('No Hub attached')end
return 'No Hub attached'
local result = TI_Innovator_port:write(data .. '\n')
if result then addMsg(tostring(data)..': '.. tostring(result))
else addMsg(tostring(data)) end
return result
function TI_Innovator.Read(bytes_to_read)
if not TI_Innovator_port thenend
return "No TI Hub attached"end
return TI_Innovator_port:read(bytes_to_read)
function TI_Innovator.request(request)
if not TI_Innovator_port thenend
return "No TI Hub attached"end
local result = TI_Innovator_port:write(request .. '\n')
if result then addMsg(tostring(request) .. ': '.. tostring(result))
else addMsg(tostring(request)) end
result = TI_Innovator_port:read()
addMsg('read() '.. tostring(result))
if result then
addMsg('Error sending request: ' .. tostring(request))end
return result
function TI_Innovator.isConnected()
if not TI_Innovator_port thenend
return falseend
return TI_Innovator_port:getState() == asi.CONNECTED
function TI_Innovator.getName()
if not TI_Innovator_port thenend
return "No TI Hub attached"end
return TI_Innovator_port:getName()
function TI_Innovator.getIdentifier()
if not TI_Innovator_port thenend
return "No TI Hub attached"end
return TI_Innovator_port:getIdentifier()
-- INTERFACE -- ENDS --
-- Wait for the ASI to be up and running
asi.addStateListener(asiStateListener)
end
------------------------------------------------------------------------
notes_aliens = {392,440,349,175,261}
times_aliens = {1,1,1,1,1}
notes_bgame = {262,523,440,392,330,392,294,262,523,440,392,330,392,415,440,415,440,330,349,392,440,349,294,440,440,440,494,523,587,494,440,392,349,294,262,523,440,392,330,392,294,262,294,330,349,392,440,440,494,523,523,523,494,440,392,370,392,440,494,523}
times_bgame = {2,4,4,4,4,1.333333333,1.333333333,2,4,4,4,4,1,4,4,4,4,4,4,4,2,4,1.333333333,2,4,4,4,4,4,4,4,4,4,4,2,4,4,4,4,1.333333333,1.333333333,2,4,4,4,4,1,4,4,1.333333333,1.333333333,4,4,4,4,4,4,1.333333333,1.333333333,1}
notes_bday = {260,262,294,262,349,330,260,262,294,262,392,349,260,262,523,440,349,348,330,294,466,465,440,349,392,349}
times_bday = {4,4,2,2,2,1,4,4,2,2,2,1,4,4,2,2,4,4,2,1,4,4,2,2,2,1}
notes_brain = {440,466,523,440,349,392,440,349,0,392,440,349,294,330,349,294,0,294,262,261,262,261,262,0,349,330,294,294,587,523,466,440,392,349,330,331,660,587,523,466,440,392,349,348,349,348,349}
times_brain = {16,48,16,48,16,48,24,16,48,24,16,48,16,48,24,16,48,24,16,48,16,48,6,1.5,16,48,16,48,16,48,16,48,16,48,16,48,16,48,16,48,16,48,16,48,16,48,6}
notes_elise = {330,660,622,660,622,660,494,587,523,440,262,330,440,494,330,415,494,523,330,660,622,660,622,660,494,587,523,440,262,330,440,494,262,523,494,440,440}
times_elise = {4,4,4,4,4,4,4,4,4,1,4,4,4,1,4,4,4,1,4,4,4,4,4,4,4,4,4,1,4,4,4,1,4,4,4,1,1}
notes_home = {262,294,330,349,440,392,330,392,349,330,349,294,262,262}
times_home = {4,4,2,4,4,2,4,4,4,4,4,4,1,1}
notes_harmonic = {440.,495,550.,586.67,660.,733.33,806.67,880.}
notes_welltemp = {440.,493.883,554.365,587.33,659.255,739.99,830.61,880.}
times_scale = {2,2,2,2,2,2,2,2}
------------------------------------------------------------------------
Hacking the Rover™
Breadboard header connectors */
BB1 14
BB2 15
BB3 7 (ColorInput Sensor White LED)
BB4 18 (Left wheel forward)
BB5 13 (HC-SR04 Ultrasonic sensor ECHO)
BB6 12 (HC-SR04 Ultrasonic sensor TRIG)
BB7 33
BB8 40 (Left wheel back)
BB9 38 (Right wheel forward)
BB10 39 (Right wheel back)RANGER.RV
-- CONNECT RANGER 1 BB6 BB5
-- READ RANGER 1ROVER MOVEMENT:
-- CONNECT DIGITAL.OUT 4 BB4
-- CONNECT DIGITAL.OUT 8 BB8
-- CONNECT DIGITAL.OUT 9 BB9
-- CONNECT DIGITAL.OUT 10 BB10-- RV FORWARD: SET DIGITAL.OUT 4 ON SET DIGITAL.OUT 9 ON
-- RV BACKWARD: SET DIGITAL.OUT 8 ON SET DIGITAL.OUT 10 ONNote that I have chosen for simplicity to use DIGITAL.OUT to control the robot movement. As with the Norland robot, ANALOG.OUT could also have been used - and is, in fact, most likely the way that the Rover is controlled, since this command requires further input, in the form of a value for the Rover speed.
The ANALOG version of these commands might take the following form (using a value like 50 as the robot speed:
-- CONNECT ANALOG.OUT 4 BB4
-- CONNECT ANALOG.OUT 8 BB8
-- CONNECT ANALOG.OUT 9 BB9
-- CONNECT ANALOG.OUT 10 BB10-- RV FORWARD: SET ANALOG.OUT 4 50 SET ANALOG.OUT 9 50
-- RV BACKWARD: SET ANALOG.OUT 8 50 SET ANALOG.OUT 10 50Feel free to experiment yourself with such values. Try using simple TI-BASIC programs with the standard TI Rover Hub, use the Lua script given above, or the general Lua_HubBLE.tns document.
To input custom hub commands in either Lua document is easy. For the Lua script above, just store the new hub commands as a string in variable "hubStr" using Calculator or spreadsheet.
In the Lua_HubBLE.tns document, just use the text box provided to enter one or more hub commands, then press the button that appears below the text box to activate these.
With this information, it is even possible to reflash the Hub sketch with a BLE-enabled version using Energia and control your Rover remotely using the Lua_HubBLE.tns control document. As shown in the animated GIF image, a BLE-enabled Rover could even be controlled by a TI SensorTag (both Light sensor or accelerometer will work in this document), or a Vernier Go Wireless Link with accelerometer!
Remember: You can always reflash your Innovator Hub to return it to its original state, using the tools that TI has made available (just follow the Resources tab, and then "Keep your Innovator up to date").
So it is possible to explore coding the Hub in new ways!If this is something that you might like to try, or you just have further questions, please feel free to contact me!
In our next lesson, we take these ideas in a different direction to drive the Norland E3 Innovator Robot.
Home ← STEM HQ ← TI-Nspire Authoring ← TI-Nspire Scripting HQ ← Scripting Tutorial - Lesson 45