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 " Disp "FORWARD "&string(time)&" s" Send "SET RV FORWARD "&string(time) wait time Send "DISCONNECT RV "EndPrgmDefine bk(time)=Prgm
Send "CONNECT RV " Disp "BACKWARD "&string(time)&" s" Send "SET RV BACKWARD "&string(time) wait time Send "DISCONNECT RV "EndPrgmDefine lt(angle)=Prgm
Send "CONNECT RV " Disp "LEFT "&string(angle)&" DEGREES" Send "SET RV LEFT "&string(angle) wait 0.2 Send "DISCONNECT RV "EndPrgmDefine rt(angle)=Prgm
Send "CONNECT RV " Disp "RIGHT "&string(angle)&" DEGREES" Send "SET RV RIGHT "&string(angle) wait 0.2 Send "DISCONNECT RV "EndPrgmDefine polygons()=Prgm
Local m,n,i Send "CONNECT RV" Request "side length (cm)",n Request "no. sides",m n:=((n)/(20)) For i,1,mEndPrgmSend "RV FORWARD SPEED .2 M/S TIME eval(n)" Send "RV LEFT eval(360/m) DEGREES"EndForDefine auto()=Prgm
Local d 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 "EndPrgm-- 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 = 20
local 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 10 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") thenendhubStrOff = hubStrOn:gsub("ON","OFF") TI_Innovator.Send(hubStrOn) addMsg(hubStrOn)elsehubStrOff = '' TI_Innovator.Send(hubStrOn) addMsg(hubStrOn) if hubStrOn:find("READ") then TI_Innovator.Read() endend 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",} toolpalette.register(Menu) screen:invalidate(){" ©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},},-- Layout Functions
function on.resize(width, height)
w = screen:width() 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 thenendfontSize = fontSize > 7 and fontSize or 7 fontSize = fontSize < 24 and fontSize or 24end fontSize1 = math.floor(h/30 + 0.5) if hh thenfontSize = fontSize > 7 and fontSize or 7 fontSize = fontSize < 24 and fontSize or 24end 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() thenaddMsg("TI Innovator Hub ready")endfunction on.paint (gc)
gc:setFont("sansserif", "r", fontSize) if TI_Innovator.isConnected() then gc:setColorRGB(0,255,0) else gc:setColorRGB(255,0,0) end if TI_Innovator.isConnected() or help == 0 thenendgc:fillRect (0, 0, w, 0.025*h) 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)elsegc:fillRect (0, 0, w, 0.025*h) 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")end 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()endTI_Innovator.Send('BEGIN\n') 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()end) screen:invalidate()function robotDisconnect()
pcall(function()endTI_Innovator.Send('BEGIN') robotConnected = false hubStrOn = 'DISCONNECT RV' hubStrOff = '' delay = 0 help = 1 runTime = var.recall("runtime") or 10 var.store("hubstr", hubStrOn)end) screen:invalidate()function rc:init(x, y, width, selected, visible)
self.x = x self.y = y self.width = width self.height = width self.visible = visible self.selected = selectedendfunction rc:contains(x, y)
local sw = self.width or self.height 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*shendfunction rc:paint(gc)
w = screen:width() h = screen:height() if self.visible == true thenendlocal x = self.x local y = self.y local width = self.width local height = self.width gc:setPen("thin", "smooth") if self.selected and hubStrOn:find("BACK") thenendgc:setPen("medium", "smooth")elsegc: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") thengc:setPen("medium", "smooth")elsegc: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") thengc:setPen("medium", "smooth")elsegc: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") thengc:setPen("medium", "smooth")elsegc: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") thengc:setPen("medium", "smooth")elsegc: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.width 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 thenendself.selected = true if x < self.x - 0.5*self.width and x > self.x - 1.5*self.widthend screen:invalidate()and y < self.y + 0.5*self.width and y > self.y - 0.5*self.width then lt(0.5)elseif x < self.x + 1.5*self.width and x > self.x + 0.5*self.widthand y < self.y + 1.5*self.width and y > self.y - 0.5*self.width then rt(0.5)elseif x < self.x + 0.5*self.width and x > self.x - 0.5*self.widthand y < self.y + 1.5*self.width and y > self.y + 0.5*self.width then bk(1)elseif x < self.x + 0.5*self.width and x > self.x - 0.5*self.widthand y < self.y - 0.5*self.width and y > self.y - 1.5*self.width then fd(1)elseon.escapeKey()endfunction rc:mouseUp(x, y)
robotDisconnect() self.selected = false screen:invalidate()end-- TI Innovator User set up
function on.arrowKey(key)
if key == "down" thenendbk(runTime)elseif key == "up" thenfd(runTime)elseif key == "left" thenlt(15)elsert(15)end screen:invalidate()function on.help()
help = 1 - help screen:invalidate()endfunction on.charIn(ch)
if ch == "a" then autoDrive() 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()endfunction on.escapeKey()
TI_Innovator.Send(hubStrOff) robotDisconnect() on.resize() screen:invalidate()endfunction on.enterKey()
robotConnect() screen:invalidate()endfunction on.mouseDown(x, y)
if robotControls.visible and robotControls:contains(x, y) thenendrobotControls:mouseDown(x, y)elseTI_Innovator.Send(hubStrOn) addMsg(hubStrOn) if hubStrOn:find("READ") then TI_Innovator.Read() endend screen:invalidate()function on.mouseUp (x,y)
if robotControls.visible and robotControls:contains(x, y) thenendrobotControls:mouseUp(x, y)elsetimeStr = '' help = 0 TI_Innovator.Send(hubStrOff) addMsg(hubStrOff) screen:invalidate()end screen:invalidate()function str2list(input, def)
local list = {} if input:find(def) thenendlist = input:split(def) table.foreachi(list,print)elselist = {input}end return listfunction 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. if tonumber(rxValue) thenendrxValue = math.floor(100*rxValue+0.5)/100 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 thenend if hubStrOn:find("RV SWITCH") thenfor k = 1, #list doendif tonumber(list[k]) then rxValue = tonumber(list[k]) TI_Innovator.Send("SET SOUND "..100*tonumber(rxValue).." 0.1") break endendif tonumber(rxValue) and tonumber(rxValue) == 1 thenend screen:invalidate()robotConnected = true addMsg("ROBOT connected") hubStrOn = ""elserobotConnected = false addMsg("ROBOT not connected")endfunction 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 here addMsg("TI_Innovator Hub connected") on.resize() TI_Innovator.Send(hubStrOff) TI_Innovator.Send("BEGIN\n") screen:invalidate()endfunction wait(input)
endif input then delay = input end time_step = 0.1 if delay >= 0 then
timeStr = "Wait Time: "..delay.." seconds" 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)elseTI_Innovator.Send(hubStrOff) delay = 0end 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..")" 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.5end screen:invalidate()function alarm(rep,waitValue)
local tone = 220 if waitValue then delay = waitValue end if rep then repeats = rep end if repeats > 0 thenendtimeStr = "alarm("..(math.floor(repeats+0.5))..", "..delay..")" 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.5end screen:invalidate()function waitTone()
if not list1 then list1 = var.recall("list1") end if not list2 then list2 = var.recall("list2") end if list1 and #list1 > 0 and list2 and #list2 > 0 thenendif I <= #list1 and list1[I] and list2[I] then -- don't go past the lenght of the arrayend screen:invalidate()if list1[I] and list2[I] thenelselocal str = "SET SOUND "..list1[I]*2^(key/12).." TIME "..math.floor(100/(list2[I])+0.5)/100 hubStrOn = str TI_Innovator.Send(str) var.store("hubstr", hubStrOn) addMsg(hubStrOn) oneShotTimer((tempo/list2[I])+20, waitTone) I = I + 1endhubStrOn = "" hubStrOff = "" addMsg(hubStrOff)endfunction playTone(list1, list2)
waitTone() screen:invalidate()end-- Robot Functions
function fd(input)
if not robotConnected then robotConnect() end addMsg("Rover FORWARD "..input) TI_Innovator.Send('SET RV FORWARD '..input) screen:invalidate()endfunction bk(input)
if not robotConnected then robotConnect() end addMsg("Rover BACKWARD "..input) TI_Innovator.Send('SET RV BACKWARD '..input) screen:invalidate()endfunction lt(input)
if not robotConnected then robotConnect() end addMsg("Rover LEFT "..input.." DEGREES") TI_Innovator.Send('SET RV LEFT '..input..' DEGREES') screen:invalidate()endfunction rt(input)
if not robotConnected then robotConnect() end addMsg("Rover RIGHT "..input.." DEGREES") TI_Innovator.Send('SET RV RIGHT '..input..' DEGREES') screen:invalidate()endfunction autoDrive()
if not robotConnected then robotConnect() end TI_Innovator.Send("READ RV.RANGER ") TI_Innovator.Read() if tonumber(rxValue) and tonumber(rxValue) > 0.1 thenendif tonumber(rxValue) > 0.3 thenelseTI_Innovator.Send('SET RV FORWARD '..time_step) addMsg("ROBOT FORWARD")elseTI_Innovator.Send('SET RV BACKWARD '..time_step) addMsg("ROBOT BACK" ) TI_Innovator.Send('SET RV RIGHT 30 DEGREES') addMsg("ROBOT RIGHT")end oneShotTimer(1000*time_step,autoDrive)TI_Innovator.Send('SET RV STOP')end screen:invalidate()function poly(sides, length)
if not robotConnected then robotConnect() end 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 thenendaddMsg('SET RV FORWARD '..secs) 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)elseaddMsg('SET RV LEFT '..angle..' DEGREES') TI_Innovator.Send('SET RV LEFT '..angle..' DEGREES') TI_Innovator.Send('SET RV STOP') delay = 0end 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 = nil
local 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 thencurrentTimer = nil timerStop()end 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') returnendaddMsg('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 readCallback
function notifyEvent(event)
addMsg('notifying '.. event) if stateCallback thenendstateCallback(event)elseaddMsg('no callback registered')endfunction startScanning()
if isASIavailable thenendasi.startScanning(portFoundListener) notifyEvent('scanning')endfunction stopScanning()
handshake_port = nil portFoundList = { } asi.stopScanning()endfunction asiStateListener(asiState)
if asi.ON == asiState thenendif state == 'active' thenelseif asi.UNSUPPORTED == asiState thenstartScanning()endnotifyEvent(asi.UNSUPPORTED)endfunction portFoundListener(portFound)
table.insert(portFoundList, portFound) if not TI_Innovator_port and not handshake_port thenendhandshake_port = portFoundList[1] oneShotTimer(100, handshake_port.connect, handshake_port, portStateListener)endfunction portStateListener(reportedPort, event, error_msg)
if asi.CONNECTED == event thenend-- configure port for handshake reportedPort:setWriteListener(handshake_writeListener) reportedPort:setReadListener(handshake_readListener) reportedPort:setReadTimeout(500) handshakeState = 'handshake' -- write handshake greeting oneShotTimer(200, reportedPort.write, reportedPort, HANDSHAKE_GREETING)elseif asi.CONNECTING_FAILED == event thenif reportedPort == handshake_port thenelseif asi.DISCONNECTED == event thentable.remove(portFoundList, 1) if #portFoundList>0 thenelseif reportedPort == TI_Innovator_port thenhandshake_port = portFoundList[1] handshake_port:connect(portStateListener)elsehandshake_port = nilendTI_Innovator_port = nil asi.startScanning(portFoundListener)endif reportedPort == TI_Innovator_port thenendif state == 'active' thenendif reportedPort:getState() == asi.DISCONNECTED thennotifyEvent('disconnected')reportedPort:connect(portStateListener)elseTI_Innovator_port = nil asi.startScanning(portFoundListener)endfunction handshake_writeListener(reportedPort, error_msg)
if error_msg thenendreturnend if 'handshake' == handshakeState thenreportedPort:read(#HANDSHAKE_ANSWER+2)endfunction handshake_readListener(reportedPort, error_msg)
if error_msg thenendreturnend local answer = reportedPort:getValue() if 'handshake' == handshakeState then-- Validate answer if answer and answer:find(HANDSHAKE_ANSWER) thenelseif 'ready' == handshakeState thenstopScanning() handshakeState = 'ready' reportedPort:write('BEGIN\n') reportedPort:read(7)elsereportedPort:disconnect() table.remove(portFoundList, 1) if #portFoundList>0 thenendhandshake_port = portFoundList[1] handshake_port:connect(portStateListener)elsehandshake_port = nilendif answer and answer:find('READY') thenend-- Configure port for normal use TI_Innovator_port = reportedPort TI_Innovator_port:setReadTimeout(readTimeout) TI_Innovator.setWriteListener(SendCallback) TI_Innovator.setReadListener(readCallback) -- Notify launchpad is ready notifyEvent('ready')end-- INTERFACE -- BEGINS --
function TI_Innovator.connect()
state = 'active' startScanning()endfunction TI_Innovator.disconnect()
state = 'inactive' if isASIavailable thenendif TI_Innovator_port thenendTI_Innovator_port:disconnect() TI_Innovator_port = nilend stopScanning()function TI_Innovator.setWriteListener(newWriteCallback)
writeCallback = newWriteCallback if TI_Innovator_port thenendTI_Innovator_port:setWriteListener(writeCallback)endfunction TI_Innovator.setReadListener(newReadCallback, newReadObject)
readCallback = newReadCallback if TI_Innovator_port thenendTI_Innovator_port:setReadListener(readCallback)endfunction TI_Innovator.setBaudRate(newBaudRate)
baudRate = newBaudRate if TI_Innovator_port thenendTI_Innovator_port:setBaudRate(baudRate)endfunction TI_Innovator.setReadTimeout(newReadTimeout)
readTimeout = newReadTimeout if TI_Innovator_port thenendTI_Innovator_port:setReadTimeout(readTimeout)endfunction TI_Innovator.Send(data)
if not TI_Innovator_port thenendaddMsg('No Hub attached') return 'No Hub attached'end local result = TI_Innovator_port:write(data .. '\n') if result then addMsg(tostring(data)..': '.. tostring(result)) end return resultfunction TI_Innovator.Read(bytes_to_read)
if not TI_Innovator_port thenendreturn "No TI Hub attached"end return TI_Innovator_port:read(bytes_to_read)function TI_Innovator.request(request)
if not TI_Innovator_port thenendreturn "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 thenaddMsg('Error sending request: ' .. tostring(request))end return resultfunction TI_Innovator.isConnected()
if not TI_Innovator_port thenendreturn falseend return TI_Innovator_port:getState() == asi.CONNECTEDfunction TI_Innovator.getName()
if not TI_Innovator_port thenendreturn "No TI Hub attached"end return TI_Innovator_port:getName()function TI_Innovator.getIdentifier()
if not TI_Innovator_port thenendreturn "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 = 20
local 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 10 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") thenendhubStrOff = hubStrOn:gsub("ON","OFF") TI_Innovator.Send(hubStrOn) addMsg(hubStrOn)elsehubStrOff = '' TI_Innovator.Send(hubStrOn) addMsg(hubStrOn) if hubStrOn:find("READ") then TI_Innovator.Read() endend 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",} toolpalette.register(Menu) screen:invalidate(){" ©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},},-- Layout Functions
function on.resize(width, height)
w = screen:width() 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 thenendfontSize = fontSize > 7 and fontSize or 7 fontSize = fontSize < 24 and fontSize or 24end fontSize1 = math.floor(h/30 + 0.5) if hh thenfontSize = fontSize > 7 and fontSize or 7 fontSize = fontSize < 24 and fontSize or 24end 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() thenaddMsg("TI Innovator Hub ready")endfunction on.paint (gc)
gc:setFont("sansserif", "r", fontSize) if TI_Innovator.isConnected() then gc:setColorRGB(0,255,0) else gc:setColorRGB(255,0,0) end if TI_Innovator.isConnected() thenendgc:fillRect (0, 0, w, 0.025*h) 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)elsegc:fillRect (0, 0, w, 0.025*h) 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")end 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()endTI_Innovator.Send('BEGIN\n') 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()end) screen:invalidate()function robotDisconnect()
pcall(function()endTI_Innovator.Send('BEGIN') robotConnected = false hubStrOn = 'DISCONNECT RV' hubStrOff = '' delay = 0 runTime = var.recall("runtime") or 10 var.store("hubstr", hubStrOn)end) screen:invalidate()function rc:init(x, y, width, selected, visible)
self.x = x self.y = y self.width = width self.height = width self.visible = visible self.selected = selectedendfunction rc:contains(x, y)
local sw = self.width or self.height 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*shendfunction rc:paint(gc)
w = screen:width() h = screen:height() if self.visible == true thenendlocal x = self.x local y = self.y local width = self.width local height = self.width gc:setPen("thin", "smooth") if self.selected and hubStrOn:find("BACK") thenendgc:setPen("medium", "smooth")elsegc: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") thengc:setPen("medium", "smooth")elsegc: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") thengc:setPen("medium", "smooth")elsegc: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") thengc:setPen("medium", "smooth")elsegc: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") thengc:setPen("medium", "smooth")elsegc: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.width 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 thenendself.selected = true if x < self.x - 0.5*self.width and x > self.x - 1.5*self.widthend screen:invalidate()and y < self.y + 0.5*self.width and y > self.y - 0.5*self.width then lt(0.5)elseif x < self.x + 1.5*self.width and x > self.x + 0.5*self.widthand y < self.y + 1.5*self.width and y > self.y - 0.5*self.width then rt(0.5)elseif x < self.x + 0.5*self.width and x > self.x - 0.5*self.widthand y < self.y + 1.5*self.width and y > self.y + 0.5*self.width then bk(1)elseif x < self.x + 0.5*self.width and x > self.x - 0.5*self.widthand y < self.y - 0.5*self.width and y > self.y - 1.5*self.width then fd(1)elseon.escapeKey()endfunction rc:mouseUp(x, y)
robotDisconnect() self.selected = false screen:invalidate()end-- TI Innovator User set up
function on.arrowKey(key)
if key == "down" thenendbk(runTime)elseif key == "up" thenfd(runTime)elseif key == "left" thenlt(15)elsert(15)end screen:invalidate()function on.help()
help = 1 - help screen:invalidate()endfunction on.charIn(ch)
if ch == "a" then autoDrive() 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()endfunction on.escapeKey()
TI_Innovator.Send(hubStrOff) robotDisconnect() on.resize() screen:invalidate()endfunction on.enterKey()
robotConnect() screen:invalidate()endfunction on.mouseDown(x, y)
if robotControls.visible and robotControls:contains(x, y) thenendrobotControls:mouseDown(x, y)elseTI_Innovator.Send(hubStrOn) addMsg(hubStrOn) if hubStrOn:find("READ") then TI_Innovator.Read() endend screen:invalidate()function on.mouseUp (x,y)
if robotControls.visible and robotControls:contains(x, y) thenendrobotControls:mouseUp(x, y)elsetimeStr = '' help = 0 TI_Innovator.Send(hubStrOff) addMsg(hubStrOff) screen:invalidate()end screen:invalidate()function str2list(input, def)
local list = {} if input:find(def) thenendlist = input:split(def) table.foreachi(list,print)elselist = {input}end return listfunction 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. if tonumber(rxValue) thenendrxValue = math.floor(100*rxValue+0.5)/100 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 thenend if hubStrOn:find("RV SWITCH") thenfor k = 1, #list doendif tonumber(list[k]) then rxValue = tonumber(list[k]) TI_Innovator.Send("SET SOUND "..100*tonumber(rxValue).." 0.1") break endendif tonumber(rxValue) and tonumber(rxValue) == 1 thenend screen:invalidate()robotConnected = true addMsg("ROBOT connected") hubStrOn = ""elserobotConnected = false addMsg("ROBOT not connected")endfunction 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 here addMsg("TI_Innovator Hub connected") on.resize() TI_Innovator.Send(hubStrOff) TI_Innovator.Send("BEGIN\n") screen:invalidate()endfunction wait(input)
endif input then delay = input end time_step = 0.1 if delay >= 0 then
timeStr = "Wait Time: "..delay.." seconds" 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)elseTI_Innovator.Send(hubStrOff) delay = 0end 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..")" 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.5end screen:invalidate()function alarm(rep,waitValue)
local tone = 220 if waitValue then delay = waitValue end if rep then repeats = rep end if repeats > 0 thenendtimeStr = "alarm("..(math.floor(repeats+0.5))..", "..delay..")" 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.5end screen:invalidate()function waitTone()
if not list1 then list1 = var.recall("list1") end if not list2 then list2 = var.recall("list2") end if list1 and #list1 > 0 and list2 and #list2 > 0 thenendif I <= #list1 and list1[I] and list2[I] then -- don't go past the lenght of the arrayend screen:invalidate()if list1[I] and list2[I] thenelselocal str = "SET SOUND "..list1[I]*2^(key/12).." TIME "..math.floor(100/(list2[I])+0.5)/100 hubStrOn = str TI_Innovator.Send(str) var.store("hubstr", hubStrOn) addMsg(hubStrOn) oneShotTimer((tempo/list2[I])+20, waitTone) I = I + 1endhubStrOn = "" hubStrOff = "" addMsg(hubStrOff)endfunction playTone(list1, list2)
waitTone() screen:invalidate()end-- ROBOT COMMANDS BEGIN
function fd(input)
if not robotConnected then robotConnect() end addMsg("Rover FORWARD "..input) TI_Innovator.Send('SET RV FORWARD '..input) screen:invalidate()endfunction bk(input)
if not robotConnected then robotConnect() end addMsg("Rover BACKWARD "..input) TI_Innovator.Send('SET RV BACKWARD '..input) screen:invalidate()endfunction lt(input)
if not robotConnected then robotConnect() end addMsg("Rover LEFT "..input.." DEGREES") TI_Innovator.Send('SET RV LEFT '..input..' DEGREES') screen:invalidate()endfunction rt(input)
if not robotConnected then robotConnect() end addMsg("Rover RIGHT "..input.." DEGREES") TI_Innovator.Send('SET RV RIGHT '..input..' DEGREES') screen:invalidate()endfunction autoDrive()
if not robotConnected then robotConnect() end TI_Innovator.Send("READ RV.RANGER ") TI_Innovator.Read() if tonumber(rxValue) and tonumber(rxValue) > 0.1 thenendif tonumber(rxValue) > 0.3 thenelseTI_Innovator.Send('SET RV FORWARD '..time_step) addMsg("ROBOT FORWARD")elseTI_Innovator.Send('SET RV BACKWARD '..time_step) addMsg("ROBOT BACK" ) TI_Innovator.Send('SET RV RIGHT 30 DEGREES') addMsg("ROBOT RIGHT")end oneShotTimer(1000*time_step,autoDrive)TI_Innovator.Send('SET RV STOP')end screen:invalidate()function poly(sides, length)
if not robotConnected then robotConnect() end 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 thenendaddMsg('SET RV FORWARD '..secs) 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)elseaddMsg('SET RV LEFT '..angle..' DEGREES') TI_Innovator.Send('SET RV LEFT '..angle..' DEGREES') TI_Innovator.Send('SET RV STOP') delay = 0end rxValue = delay screen:invalidate()-- oneShotTimer BEGINS
local timerstart = timer.start local timerstop = timer.stop timer.start = nil timer.stop = nil local currentTimer = nil
local 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 thencurrentTimer = nil timerStop()end 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') returnendaddMsg('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 readCallback
function notifyEvent(event)
addMsg('notifying '.. event) if stateCallback thenendstateCallback(event)elseaddMsg('no callback registered')endfunction startScanning()
if isASIavailable thenendasi.startScanning(portFoundListener) notifyEvent('scanning')endfunction stopScanning()
handshake_port = nil portFoundList = { } asi.stopScanning()endfunction asiStateListener(asiState)
if asi.ON == asiState thenendif state == 'active' thenelseif asi.UNSUPPORTED == asiState thenstartScanning()endnotifyEvent(asi.UNSUPPORTED)endfunction portFoundListener(portFound)
addMsg('portFoundListener '.. portFound:getName()) table.insert(portFoundList, portFound) if not TI_Innovator_port and not handshake_port thenendhandshake_port = portFoundList[1] oneShotTimer(100, handshake_port.connect, handshake_port, portStateListener)endfunction portStateListener(reportedPort, event, error_msg)
addMsg('portStateListener '..reportedPort:getName()..' '..event) if asi.CONNECTED == event thenend-- configure port for handshake 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)elseif asi.CONNECTING_FAILED == event thenif reportedPort == handshake_port thenelseif asi.DISCONNECTED == event thentable.remove(portFoundList, 1) if #portFoundList>0 thenelseif reportedPort == TI_Innovator_port thenhandshake_port = portFoundList[1] handshake_port:connect(portStateListener)elsehandshake_port = nilendTI_Innovator_port = nil asi.startScanning(portFoundListener)endif reportedPort == TI_Innovator_port thenendif state == 'active' thenendif reportedPort:getState() == asi.DISCONNECTED thennotifyEvent('disconnected')reportedPort:connect(portStateListener)elseTI_Innovator_port = nil asi.startScanning(portFoundListener)endfunction handshake_writeListener(reportedPort, error_msg)
if error_msg thenendaddMsg('handshake_writeListener '..error_msg) returnend if 'handshake' == handshakeState thenreportedPort:read(#HANDSHAKE_ANSWER+2)endfunction handshake_readListener(reportedPort, error_msg)
if error_msg thenendaddMsg('handshake_writeListener '..error_msg) returnend local answer = reportedPort:getValue() if 'handshake' == handshakeState then-- Validate answer if answer and answer:find(HANDSHAKE_ANSWER) thenelseif 'ready' == handshakeState thenaddMsg("HANDSHAKE_ANSWER: "..HANDSHAKE_ANSWER) stopScanning() handshakeState = 'ready' reportedPort:write('BEGIN\n') reportedPort:read(7)elsereportedPort:disconnect() table.remove(portFoundList, 1) if #portFoundList>0 thenendhandshake_port = portFoundList[1] handshake_port:connect(portStateListener)elsehandshake_port = nilendif answer and answer:find('READY') thenend-- Configure port for normal use TI_Innovator_port = reportedPort TI_Innovator_port:setReadTimeout(readTimeout) TI_Innovator.setWriteListener(SendCallback) TI_Innovator.setReadListener(readCallback) -- Notify launchpad is ready notifyEvent('ready')end-- INTERFACE -- BEGINS --
function TI_Innovator.connect()
state = 'active' startScanning()endfunction TI_Innovator.disconnect()
state = 'inactive' if isASIavailable thenendif TI_Innovator_port thenendTI_Innovator_port:disconnect() TI_Innovator_port = nilend stopScanning()function TI_Innovator.setWriteListener(newWriteCallback)
writeCallback = newWriteCallback if TI_Innovator_port thenendTI_Innovator_port:setWriteListener(writeCallback)endfunction TI_Innovator.setReadListener(newReadCallback, newReadObject)
readCallback = newReadCallback if TI_Innovator_port thenendTI_Innovator_port:setReadListener(readCallback)endfunction TI_Innovator.setBaudRate(newBaudRate)
baudRate = newBaudRate if TI_Innovator_port thenendTI_Innovator_port:setBaudRate(baudRate)endfunction TI_Innovator.setReadTimeout(newReadTimeout)
readTimeout = newReadTimeout if TI_Innovator_port thenendTI_Innovator_port:setReadTimeout(readTimeout)endfunction TI_Innovator.Send(data)
if not TI_Innovator_port thenendaddMsg('No Hub attached') return 'No Hub attached'end local result = TI_Innovator_port:write(data .. '\n') if result then addMsg(tostring(data)..': '.. tostring(result)) else addMsg(tostring(data)) end return resultfunction TI_Innovator.Read(bytes_to_read)
if not TI_Innovator_port thenendreturn "No TI Hub attached"end return TI_Innovator_port:read(bytes_to_read)function TI_Innovator.request(request)
if not TI_Innovator_port thenendreturn "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 thenaddMsg('Error sending request: ' .. tostring(request))end return resultfunction TI_Innovator.isConnected()
if not TI_Innovator_port thenendreturn falseend return TI_Innovator_port:getState() == asi.CONNECTEDfunction TI_Innovator.getName()
if not TI_Innovator_port thenendreturn "No TI Hub attached"end return TI_Innovator_port:getName()function TI_Innovator.getIdentifier()
if not TI_Innovator_port thenendreturn "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 1
ROVER 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 ON
Note 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 50
Feel 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