Home ← STEM HQ ← TI-Nspire Authoring ← TI-Nspire Scripting HQ ← Scripting Tutorial - Lesson 47
Scripting Tutorial - Lesson 47: Lua Scripting and the TI Innovator™ Hub:
7. Build your own Innovator™ Hub Robot
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 for this tutorial
Texas Instruments TI-Nspire Scripting Support Page
Scripting for the Innovator Hub: Lesson 7: Build your own Innovator™ Hub Robot
As in the previous tutorial, we see two different ways to use the Innovator Hub for a "practical" purpose - this time, driving a home-made robot: using a Lua script, and also using TI-BASIC.
This robot vehicle is driven by two light servo motors. In order to limit the power demand, we will connect the voltage lead for both of these to the one 3.3V BB connection (I "piggy-backed" one onto the other). Using the more usual 5V BB9 port would require the other wheel to also use 5 volts, and together this is too much, so using 3.3 volts for each gives us a more reliable (if slightly slower) experience.
The best option (if not the simplest) is to run the servos from an external battery. Use either a 9 volt "transistor" (D-type) battery or a 4-pack battery case. Either way, you will have a positive (red) and a negative (ground, black) lead. Using a breadboard (or even part of a breadboard), connect the red (positive) lead on the same line as the red (voltage) leads from your servos. The black ground lead needs to be connected to a ground pin on your board, along with the black/ground leads from the servos, connected to other ground pins (I just used three ground BB pins). Connect the other (signal) leads from the servos to the appropriate pins on your board, and you now have a circuit which runs through your board but with no risk of frying it!
In addition to sending instructions to two attached servo motors to go forward, back, left and right, we also extend the activity to have the robot follow a bright light using the on-board brightness sensor, and auto-drive to avoid obstacles using an ultrasonic ranger (if you have one).
As with LaunchPad lesson 9 (in which we built a BLE robot using a bare MSP432 LaunchPad board and spare LEGO from my grandchildrens' toybox) we will supplement our main chassis - in this case, our TI Innovator™ Hub - with a few extra components:
Two servo motors - I used Feetech FS90R micro continuous rotation servo from eBay and paid around $AUD6 each (total around $USD10) - NOTE: NOT the identical-looking Feetech FS90 which will NOT work for our purposes!
![]()
Pololu wheel are designed specifically for the FeeTech FS90R servo motor.
You will also need a light-weight power source.
![]()
I found a great 2500 mAh power bank on eBay for $AUD15! (around $USD10)
The form factor is ideal for our robot -it sits perfectly on top of the Innovator.
![]()
We add one new variable: drive.
Our menu continues to grow with more examples.
- No changes, other than adding values to the new variables.
Note the changes to mouseDown and mouseUp.
are defined here: individually for the four directions, and then the lightSeeker and autoDrive functions.
- 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(t)=Prgm
Send "BEGIN " DelVar iostr.str0:GetStr iostr.str0:Disp iostr.str0 Disp "FORWARD" Send "CONNECT SERVO 1 BB9 " Send "CONNECT SERVO 2 BB10 " Send "SET SERVO 1 CCW 100 "&" TIME "&string(t) Send "SET SERVO 2 CW 100 "&" TIME "&string(t) EndPrgmDefine bk(t)=Prgm
Send "BEGIN " DelVar iostr.str0:GetStr iostr.str0:Disp iostr.str0 Send "CONNECT SERVO 1 BB9 " Send "CONNECT SERVO 2 BB10 " Send "SET SERVO 1 CW 100 "&" TIME "&string(t) Send "SET SERVO 2 CCW 100 "&" TIME "&string(t) EndPrgmDefine lt(t)=Prgm
Send "BEGIN " DelVar iostr.str0:GetStr iostr.str0:Disp iostr.str0 Send "CONNECT SERVO 1 BB9 " Send "CONNECT SERVO 2 BB10 " Send "SET SERVO 1 CW 100 "&" TIME "&string(t) Send "SET SERVO 2 CW 100 "&" TIME "&string(t) EndPrgmDefine rt(t)=Prgm
Send "BEGIN " DelVar iostr.str0:GetStr iostr.str0:Disp iostr.str0 Send "CONNECT SERVO 1 BB9 " Send "CONNECT SERVO 2 BB10 " Send "SET SERVO 1 CCW 100 "&" TIME "&string(t) Send "SET SERVO 2 CCW 100 "&" TIME "&string(t) EndPrgmDefine lightseeker(m,x)=Prgm
Send "BEGIN " DelVar iostr.str0:GetStr iostr.str0:Disp iostr.str0 Local b b:=0 Send "CONNECT SERVO 1 BB9 " Send "CONNECT SERVO 2 BB10 " Send "READ BRIGHTNESS " Get b Disp "Brightness "&string(b) Send "SET SOUND eval(b*100) 0.1" While b>m Send "READ BRIGHTNESS " Get b Disp "Brightness "&string(b) Send "SET SOUND eval(b*100) 0.5" If b>x Then Disp "FORWARD" Send "SET SERVO 1 CCW 100 TIME 1 " Send "SET SERVO 2 CW 100 TIME 1 " Wait 1 Else Disp "BACK" Send "SET SERVO 1 CW 100 TIME 0.5 " Send "SET SERVO 2 CCW 100 TIME 0.5 " Wait 0.5 Disp "RIGHT" Send "SET SERVO 1 CCW 100 TIME 0.5 " Send "SET SERVO 2 CCW 100 TIME 0.5 " Wait 0.5 EndIf EndWhile EndPrgmDefine auto()=Prgm
Send "BEGIN " DelVar iostr.str0:GetStr iostr.str0:Disp iostr.str0 Local d d:=0 Send "CONNECT RANGER 1 IN1 " Send "CONNECT SERVO 1 BB9 " Send "CONNECT SERVO 2 BB10 " Send "READ RANGER 1 " Get d Disp "Distance "&string(d*10)&" cm" Send "SET SOUND eval(d*1000) 0.1" While d>0.15 Send "READ RANGER 1 " Get d Disp "Distance "&string(d*10)&" cm" Send "SET SOUND eval(d*1000) 0.5" If d>0.3 Then Disp "FORWARD" Send "SET SERVO 1 CCW 100 TIME 1 " Send "SET SERVO 2 CW 100 TIME 1 " Wait 1 Else Disp "BACK" Send "SET SERVO 1 CW 100 TIME 0.5 " Send "SET SERVO 2 CCW 100 TIME 0.5 " Wait 0.5 Disp "RIGHT" Send "SET SERVO 1 CCW 100 TIME 0.5 " Send "SET SERVO 2 CCW 100 TIME 0.5 " Wait 0.5 EndIf EndWhile EndPrgm end-- TI Innovator Init Values
platform.apilevel = '2.7' local screen = platform.window local date = "021517"
require 'color' pcall(function() require 'asi' end)
local isASIavailable = false local hubStrOn, hubStrOff, msgStr, rxValue, timeStr, delay, repeats, drive
local tempo, key, I local list1, list2, index, dataList = {}, {}, {}, {} var.store("index", index) var.store("dataList", dataList)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(){" ©2017 Compass Learning Technologies", function() end}, {" Version "..date, function() end}, {" Contact: steve@compasstech.com.au ", function() 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) end}, {"SET COLOR.RED ON/OFF", function() hubStrOn = "SET COLOR.RED ON" hubStrOff = "SET COLOR.RED OFF" TI_Innovator.Send(hubStrOn) end}, {"SET COLOR.GREEN ON/OFF", function() hubStrOn = "SET COLOR.GREEN ON" hubStrOff = "SET COLOR.GREEN OFF" TI_Innovator.Send(hubStrOn) end}, {"SET COLOR.BLUE ON/OFF", function() hubStrOn = "SET COLOR.BLUE ON" hubStrOff = "SET COLOR.BLUE OFF" TI_Innovator.Send(hubStrOn) end}, {"SET SOUND 220 5", function() hubStrOn = "SET SOUND 220 5" hubStrOff = "SET SOUND 0 1" TI_Innovator.Send(hubStrOn) 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" 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" end}, {"SET SERVO 1 CW 50 5 (BB9)", function() TI_Innovator.Send("CONNECT SERVO 1 BB9") hubStrOn = "SET SERVO 1 CW 50 5" hubStrOff = "SET SERVO 1 CW 50 0" TI_Innovator.Send(hubStrOn) 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" 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" end}, }, {"READ Samples",{"READ BRIGHTNESS (default)", function() hubStrOn = "READ BRIGHTNESS" TI_Innovator.Send(hubStrOn) TI_Innovator.Read() msgStr = rxValue or hubStrOn end}, {"READ RANGER 1", function() hubStrOn = "READ RANGER 1" TI_Innovator.Send("CONNECT RANGER 1 IN1") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() msgStr = rxValue or hubStrOn end}, {"READ DHT 1", function() hubStrOn = "READ DHT 1" TI_Innovator.Send("CONNECT DHT 1 IN1") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() msgStr = rxValue or hubStrOn end}, {"READ ACCEL 1", function() hubStrOn = "READ ACCEL 1" TI_Innovator.Send("CONNECT ACCEL 1 I2C") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() msgStr = rxValue or hubStrOn end}, {"READ BAROMETER", function() hubStrOn = "READ BAROMETER" TI_Innovator.Send("CONNECT BAROMETER I2C") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() msgStr = rxValue or hubStrOn 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 = hubStrOn 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 = hubStrOn end},}, {"Select Sound",{"C4", function() hubStrOn = "SET SOUND 262 TIME 1" TI_Innovator.Send(hubStrOn) hubStrOff = "SET SOUND 0 1" msgStr = hubStrOff end}, {"A4", function() hubStrOn = "SET SOUND 440 TIME 1" TI_Innovator.Send(hubStrOn) hubStrOff = "SET SOUND 0 1" msgStr = hubStrOff end}, {"C5", function() hubStrOn = "SET SOUND 523 TIME 1" TI_Innovator.Send(hubStrOn) hubStrOff = "SET SOUND 0 1" msgStr = hubStrOff 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) hubStrOff = "Aliens" msgStr = hubStrOff end}, {"BallGame (sample)", function() tempo = 1000 I=1 list1 = notes_bgame list2 = times_bgame playTone(list1,list2) hubStrOff = "Take me out to the Ball Game" msgStr = hubStrOff end}, {"Happy Birthday (sample)", function() tempo = 1000 I=1 list1 = notes_bday list2 = times_bday playTone(list1,list2) hubStrOff = "Happy Birthday" msgStr = hubStrOff end}, {"If I Only Had a Brain (sample)", function() tempo = 4000 I=1 list1 = notes_brain list2 = times_brain playTone(list1,list2) hubStrOff = "If I only had a brain" msgStr = hubStrOff end}, {"Fur Elise (sample)", function() tempo = 1000 I=1 list1 = notes_elise list2 = times_elise playTone(list1,list2) hubStrOff = "Fur Elise" msgStr = hubStrOff end}, {"Home on the Range (sample)", function() tempo = 1000 I=1 list1 = notes_home list2 = times_home playTone(list1,list2) hubStrOff = "Home on the Range" msgStr = hubStrOff end}, {"Well-tempered Scale", function() tempo = 1000 I=1 list1 = notes_welltemp list2 = times_scale playTone(list1,list2) hubStrOff = "Well tempered scale" msgStr = hubStrOff end}, {"Harmonic Scale", function() tempo = 1000 I=1 list1 = notes_harmonic list2 = times_scale playTone(list1,list2) hubStrOff = "Harmonic scale" msgStr = hubStrOff end},}, {"TIMER Samples",{"wait(5)", function() wait(5) end}, {"blink(5,1)", function() blink(5,1) end}, {"alarm(5,0.5)", function() alarm(5,0.5) end},}, {"Robot Samples",{"CONNECT ROBOT SERVOS (BB9/BB10)", function() showKeyBoard = false TI_Innovator.Send("CONNECT SERVO 1 BB9") TI_Innovator.Send("CONNECT SERVO 2 BB10") end}, {"ROBOT FD 1 secs", function() fd(1) end}, {"ROBOT BK 1 secs", function() bk(1) end}, {"ROBOT LT 1 secs", function() lt(1) end}, {"ROBOT RT 1 secs", function() rt(1) end}, {"AUTO drive (DISTANCE)", function() TI_Innovator.Send("CONNECT RANGER 1 IN1") drive = "RANGER" auto() end}, {"AUTO drive (BRIGHTNESS)", function() drive = "BRIGHTNESS" lightSeeker() end},},function on.arrowKey(key)
if key == "down" thenendbk(1)elseif key == "up" thenfd(1)elseif key == "left" thenlt(1)elsert(1)end screen:invalidate()function on.charIn(ch)
if ch == "l" then drive = "BRIGHTNESS" lightSeeker() elseif ch == "a" then drive = "RANGER" auto() end screen:invalidate()end-- Layout Functions
function on.resize(width, height)
w = screen:width() h = screen:height() hubStrOn, hubStrOff, msgStr, rxValue = "SET LIGHT ON", "SET LIGHT OFF", "SET LIGHT OFF", "" timeStr, delay, repeats, drive = "", 0, 1, "" tempo = 1000 key = 0 I=1 list1, list2 = {}, {} index, dataList = {}, {} var.store("index", index) var.store("dataList", dataList) if TI_Innovator.isConnected() then TI_Innovator.Send('BEGIN') addMsg("TI Innovator Hub ready") end screen:invalidate()endfunction on.paint (gc)
end gc:drawString(timeStr, 0.05*w, 0.75*h, "middle") gc:drawString(msgStr, 0.05*w, 0.85*h, "middle")if TI_Innovator.isConnected() then
gc:setColorRGB (0,255,0) gc:fillRect (0, 0, w, 0.025*h)else gc:setColorRGB (255,0,0) gc:fillRect (0, 0, w, 0.025*h) gc:drawString("Wait for connection, then", 0.1*w, 0.1*h, "middle") gc:drawString("press anywhere to activate Hub", 0.1*w, 0.2*h, "middle")gc:drawString(rxValue, 0.05*w, 0.95*h, "middle")
-- TI Innovator User set up
function on.escapeKey()
TI_Innovator.Send(hubStrOff) on.resize() screen:invalidate()endfunction on.mouseDown(x, y)
if hubStrOn:find("ROBOT") thenendif drive:find("BRIGHT") thenelselightSeeker()elseif drive:find("RANGER") thenauto()elseTI_Innovator.Send("SET SERVO 1 CCW 50 5") TI_Innovator.Send("SET SERVO 2 CW 50 5") TI_Innovator.Read()endTI_Innovator.Send(hubStrOn) -- This is an example of sending a SET command to the Hub TI_Innovator.Read() -- This is an example of sending a READ command to the Hub screen:invalidate()endfunction on.mouseUp (x,y)
if hubStrOn:find("ROBOT") thenendif drive == '' thenTI_Innovator.Send("SET SERVO 1 CCW 0 0") TI_Innovator.Send("SET SERVO 2 CW 0 0") TI_Innovator.Read() endelsetimeStr = '' TI_Innovator.Send(hubStrOff) TI_Innovator.Read() screen:invalidate()endfunction str2list(input, def) local list = {} if input:find(def) then
list = input:split(def) table.foreachi(list,print)elselist = {input}end return list endfunction 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. Note that rxValue may be numeric, list or string (hence the utility function list2str) if tonumber(rxValue) then rxValue = math.floor(100*rxValue+0.5)/100 else rxValue = tostring(rxValue) rxValue = str2list(rxValue,string.char(10))[1] end addMsg(hubStrOn) if tonumber(rxValue) then voltage = (rxValue/2^14)*3.3 end -- an example of converting a raw 14 bit ADC value into voltage. screen:invalidate()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("CONNECT SERVO 1 BB9") TI_Innovator.Send("CONNECT SERVO 2 BB10")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 if tonumber(rxValue) then -- This allows our wait function to serve as a timed data collection toolelsedataList[#dataList+1] = tonumber(rxValue) index[#index+1]=#dataList var.store("index", index) var.store("dataList", dataList)else rxValue = tostring(rxValue) rxValue = str2list(rxValue,string.char(10))[1] end oneShotTimer(1000*time_step,wait)TI_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) oneShotTimer((tempo/list2[I])+20, waitTone) I = I + 1endhubStrOn = "SET LIGHT ON" hubStrOff = "SET LIGHT OFF" addMsg(hubStrOff)endfunction playTone(list1, list2)
waitTone() screen:invalidate()endfunction fd(input)
if input thenendTI_Innovator.Send("SET SERVO 1 CCW 50 "..input) TI_Innovator.Send("SET SERVO 2 CW 50 "..input) hubStrOn = "ROBOT FORWARD" addMsg(hubStrOn) oneShotTimer(1000,fd)end hubStrOff = "ROBOT OFF" addMsg(hubStrOff) screen:invalidate()function bk(input)
if input thenendTI_Innovator.Send("SET SERVO 1 CW 50 "..input) TI_Innovator.Send("SET SERVO 2 CCW 50 "..input) hubStrOn = "ROBOT BACK" addMsg(hubStrOn) oneShotTimer(1000,bk)end hubStrOff = "ROBOT OFF" addMsg(hubStrOff) screen:invalidate()function lt(input)
if input thenendTI_Innovator.Send("SET SERVO 1 CW 50 "..input) TI_Innovator.Send("SET SERVO 2 CW 50 "..input) hubStrOn = "ROBOT LEFT" addMsg(hubStrOn) oneShotTimer(1000,lt)end hubStrOff = "ROBOT OFF" addMsg(hubStrOff) screen:invalidate()function rt(input)
if input thenendTI_Innovator.Send("SET SERVO 1 CCW 50 "..input) TI_Innovator.Send("SET SERVO 2 CCW 50 "..input) hubStrOn = "ROBOT RIGHT" addMsg(hubStrOn) oneShotTimer(1000,rt)end hubStrOff = "ROBOT OFF" addMsg(hubStrOff) screen:invalidate()function lightSeeker()
if drive:find("BRIGHT") thenendTI_Innovator.Send("READ BRIGHTNESS ") TI_Innovator.Read() if tonumber(rxValue) and tonumber(rxValue) > 0 thenend oneShotTimer(1000,lightSeeker) screen:invalidate()if tonumber(rxValue) > 0.5 thenendif tonumber(rxValue) > 10 thenelsefd(1)elsebk(1) rt(1)endfd(0) hubStrOff = "ROBOT AUTO OFF" addMsg(hubStrOff) drive = ''endfunction auto()
if drive:find("RANGER") thenendTI_Innovator.Send("READ RANGER 1 ") TI_Innovator.Read() if tonumber(rxValue) and tonumber(rxValue) > 0 thenend oneShotTimer(1000,auto) screen:invalidate()TI_Innovator.Send("SET SOUND "..1000*tonumber(rxValue).." 0.1") if tonumber(rxValue) > 0.1 thenendif tonumber(rxValue) > 0.4 thenelsefd(1)elsebk(0.5) rt(0.5)endfd(0) hubStrOff = "ROBOT AUTO OFF" addMsg(hubStrOff) drive = ''end--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)
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,476,475,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,476,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,476,440,392,349,330,331,660,587,523,476,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 = "021517"
require 'color' pcall(function() require 'asi' end)
local isASIavailable = false local hubStrOn, hubStrOff, msgStr, rxValue, timeStr, delay, repeats, drive
local tempo, key, I local list1, list2, index, dataList = {}, {}, {}, {} var.store("index", index) var.store("dataList", dataList)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(){" ©2017 Compass Learning Technologies", function() end}, {" Version "..date, function() end}, {" Contact: steve@compasstech.com.au ", function() 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) end}, {"SET COLOR.RED ON/OFF", function() hubStrOn = "SET COLOR.RED ON" hubStrOff = "SET COLOR.RED OFF" TI_Innovator.Send(hubStrOn) end}, {"SET COLOR.GREEN ON/OFF", function() hubStrOn = "SET COLOR.GREEN ON" hubStrOff = "SET COLOR.GREEN OFF" TI_Innovator.Send(hubStrOn) end}, {"SET COLOR.BLUE ON/OFF", function() hubStrOn = "SET COLOR.BLUE ON" hubStrOff = "SET COLOR.BLUE OFF" TI_Innovator.Send(hubStrOn) end}, {"SET SOUND 220 5", function() hubStrOn = "SET SOUND 220 5" hubStrOff = "SET SOUND 0 1" TI_Innovator.Send(hubStrOn) 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" 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" end}, {"SET SERVO 1 CW 50 5", function() TI_Innovator.Send("CONNECT SERVO 1 BB9") hubStrOn = "SET SERVO 1 CW 50 5" hubStrOff = "SET SERVO 1 CW 50 0" TI_Innovator.Send(hubStrOn) 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" 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" end}, }, {"READ Samples",{"READ BRIGHTNESS (default)", function() hubStrOn = "READ BRIGHTNESS" TI_Innovator.Send(hubStrOn) TI_Innovator.Read() msgStr = rxValue or hubStrOn end}, {"READ RANGER 1", function() hubStrOn = "READ RANGER 1" TI_Innovator.Send("CONNECT RANGER 1 IN1") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() msgStr = rxValue or hubStrOn end}, {"READ DHT 1", function() hubStrOn = "READ DHT 1" TI_Innovator.Send("CONNECT DHT 1 IN1") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() msgStr = rxValue or hubStrOn end}, {"READ ACCEL 1", function() hubStrOn = "READ ACCEL 1" TI_Innovator.Send("CONNECT ACCEL 1 I2C") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() msgStr = rxValue or hubStrOn end}, {"READ BAROMETER", function() hubStrOn = "READ BAROMETER" TI_Innovator.Send("CONNECT BAROMETER I2C") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() msgStr = rxValue or hubStrOn 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 = hubStrOn 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 = hubStrOn end},}, {"Select Sound",{"C4", function() hubStrOn = "SET SOUND 262 TIME 1" TI_Innovator.Send(hubStrOn) hubStrOff = "SET SOUND 0 1" msgStr = hubStrOff end}, {"A4", function() hubStrOn = "SET SOUND 440 TIME 1" TI_Innovator.Send(hubStrOn) hubStrOff = "SET SOUND 0 1" msgStr = hubStrOff end}, {"C5", function() hubStrOn = "SET SOUND 523 TIME 1" TI_Innovator.Send(hubStrOn) hubStrOff = "SET SOUND 0 1" msgStr = hubStrOff 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) hubStrOff = "Aliens" msgStr = hubStrOff end}, {"BallGame (sample)", function() tempo = 1000 I=1 list1 = notes_bgame list2 = times_bgame playTone(list1,list2) hubStrOff = "Take me out to the Ball Game" msgStr = hubStrOff end}, {"Happy Birthday (sample)", function() tempo = 1000 I=1 list1 = notes_bday list2 = times_bday playTone(list1,list2) hubStrOff = "Happy Birthday" msgStr = hubStrOff end}, {"If I Only Had a Brain (sample)", function() tempo = 4000 I=1 list1 = notes_brain list2 = times_brain playTone(list1,list2) hubStrOff = "If I only had a brain" msgStr = hubStrOff end}, {"Fur Elise (sample)", function() tempo = 1000 I=1 list1 = notes_elise list2 = times_elise playTone(list1,list2) hubStrOff = "Fur Elise" msgStr = hubStrOff end}, {"Home on the Range (sample)", function() tempo = 1000 I=1 list1 = notes_home list2 = times_home playTone(list1,list2) hubStrOff = "Home on the Range" msgStr = hubStrOff end}, {"Well-tempered Scale", function() tempo = 1000 I=1 list1 = notes_welltemp list2 = times_scale playTone(list1,list2) hubStrOff = "Well tempered scale" msgStr = hubStrOff end}, {"Harmonic Scale", function() tempo = 1000 I=1 list1 = notes_harmonic list2 = times_scale playTone(list1,list2) hubStrOff = "Harmonic scale" msgStr = hubStrOff end},}, {"TIMER Samples",{"wait(5)", function() wait(5) end}, {"blink(5,1)", function() blink(5,1) end}, {"alarm(5,0.5)", function() alarm(5,0.5) end},}, {"Robot Samples",{"CONNECT ROBOT SERVOS (BB9/BB10)", function() showKeyBoard = false TI_Innovator.Send("CONNECT SERVO 1 BB9") TI_Innovator.Send("CONNECT SERVO 2 BB10") end}, {"ROBOT FD 1 secs", function() fd(1) end}, {"ROBOT BK 1 secs", function() bk(1) end}, {"ROBOT LT 1 secs", function() lt(1) end}, {"ROBOT RT 1 secs", function() rt(1) end}, {"AUTO drive (DISTANCE)", function() TI_Innovator.Send("CONNECT RANGER 1 IN1") drive = "RANGER" auto() end}, {"AUTO drive (BRIGHTNESS)", function() drive = "BRIGHTNESS" lightSeeker() end},},function on.arrowKey(key)
if key == "down" thenendbk(1)elseif key == "up" thenfd(1)elseif key == "left" thenlt(1)elsert(1)end screen:invalidate()function on.charIn(ch)
if ch == "l" then drive = "BRIGHTNESS" lightSeeker() elseif ch == "a" then drive = "RANGER" auto() end screen:invalidate()end-- Layout Functions
function on.resize(width, height)
w = screen:width() h = screen:height() hubStrOn, hubStrOff, msgStr, rxValue = "SET LIGHT ON", "SET LIGHT OFF", "SET LIGHT OFF", "" timeStr, delay, repeats, drive = "", 0, 1, "" tempo = 1000 key = 0 I=1 list1, list2 = {}, {} index, dataList = {}, {} var.store("index", index) var.store("dataList", dataList) if TI_Innovator.isConnected() then TI_Innovator.Send('BEGIN') addMsg("TI Innovator Hub ready") end screen:invalidate()endfunction on.paint (gc)
endif TI_Innovator.isConnected() then
gc:setColorRGB (0,255,0) gc:fillRect (0, 0, w, 0.025*h)elsegc:setColorRGB (255,0,0) gc:fillRect (0, 0, w, 0.025*h) gc:drawString("Wait for connection, then", 0.1*w, 0.1*h, "middle") gc:drawString("press anywhere to activate Hub", 0.1*w, 0.2*h, "middle")end gc:drawString(timeStr, 0.05*w, 0.75*h, "middle") gc:drawString(msgStr, 0.05*w, 0.85*h, "middle")gc:drawString(rxValue, 0.05*w, 0.95*h, "middle")
-- TI Innovator User set up
function on.escapeKey()
TI_Innovator.Send(hubStrOff) on.resize() screen:invalidate()endfunction on.mouseDown(x, y)
if hubStrOn:find("ROBOT") thenendif drive:find("BRIGHT") thenelselightSeeker()elseif drive:find("RANGER") thenauto()elseTI_Innovator.Send("SET SERVO 1 CCW 50 5") TI_Innovator.Send("SET SERVO 2 CW 50 5") TI_Innovator.Read()endTI_Innovator.Send(hubStrOn) -- This is an example of sending a SET command to the Hub TI_Innovator.Read() -- This is an example of sending a READ command to the Hub screen:invalidate()endfunction on.mouseUp (x,y)
if hubStrOn:find("ROBOT") thenendif drive == '' thenTI_Innovator.Send("SET SERVO 1 CCW 0 0") TI_Innovator.Send("SET SERVO 2 CW 0 0") TI_Innovator.Read() endelsetimeStr = '' TI_Innovator.Send(hubStrOff) TI_Innovator.Read() screen:invalidate()endfunction str2list(input, def) local list = {} if input:find(def) then
list = input:split(def) table.foreachi(list,print)elselist = {input}end return list endfunction 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. Note that rxValue may be numeric, list or string (hence the utility function list2str) if tonumber(rxValue) then rxValue = math.floor(100*rxValue+0.5)/100 dataList[#dataList+1] = tonumber(rxValue) else rxValue = tostring(rxValue) rxValue = str2list(rxValue,string.char(10))[1] end addMsg(hubStrOn) if tonumber(rxValue) then voltage = (rxValue/2^14)*3.3 end -- an example of converting a raw 14 bit ADC value into voltage. screen:invalidate()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()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 if tonumber(rxValue) then -- This allows our wait function to serve as a timed data collection toolelsedataList[#dataList+1] = tonumber(rxValue) index[#index+1]=#dataList var.store("index", index) var.store("dataList", dataList)else rxValue = tostring(rxValue) rxValue = str2list(rxValue,string.char(10))[1] end oneShotTimer(1000*time_step,wait)TI_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) oneShotTimer((tempo/list2[I])+20, waitTone) I = I + 1endhubStrOn = "SET LIGHT ON" hubStrOff = "SET LIGHT OFF" addMsg(hubStrOff)endfunction playTone(list1, list2)
waitTone() screen:invalidate()end-- ROBOT COMMANDS BEGIN
function fd(input)
if input thenendTI_Innovator.Send("SET SERVO 1 CCW 50 "..input) TI_Innovator.Send("SET SERVO 2 CW 50 "..input) hubStrOn = "ROBOT FORWARD" addMsg(hubStrOn) oneShotTimer(1000,fd)end hubStrOff = "ROBOT OFF" addMsg(hubStrOff) screen:invalidate()function bk(input)
if input thenendTI_Innovator.Send("SET SERVO 1 CW 50 "..input) TI_Innovator.Send("SET SERVO 2 CCW 50 "..input) hubStrOn = "ROBOT BACK" addMsg(hubStrOn) oneShotTimer(1000,bk)end hubStrOff = "ROBOT OFF" addMsg(hubStrOff) screen:invalidate()function lt(input)
if input thenendTI_Innovator.Send("SET SERVO 1 CW 50 "..input) TI_Innovator.Send("SET SERVO 2 CW 50 "..input) hubStrOn = "ROBOT LEFT" addMsg(hubStrOn) oneShotTimer(1000,lt)end hubStrOff = "ROBOT OFF" addMsg(hubStrOff) screen:invalidate()function rt(input)
if input thenendTI_Innovator.Send("SET SERVO 1 CCW 50 "..input) TI_Innovator.Send("SET SERVO 2 CCW 50 "..input) hubStrOn = "ROBOT RIGHT" addMsg(hubStrOn) oneShotTimer(1000,rt)end hubStrOff = "ROBOT OFF" addMsg(hubStrOff) screen:invalidate()function lightSeeker()
if drive:find("BRIGHT") thenendTI_Innovator.Send("READ BRIGHTNESS ") TI_Innovator.Read() if tonumber(rxValue) and tonumber(rxValue) > 0 thenend oneShotTimer(1000,lightSeeker) screen:invalidate()if tonumber(rxValue) > 0.5 thenendif tonumber(rxValue) > 10 thenelsefd(1)elsebk(1) rt(1)endfd(0) hubStrOff = "ROBOT AUTO OFF" addMsg(hubStrOff) drive = ''endfunction auto()
if drive:find("RANGER") thenendTI_Innovator.Send("READ RANGER 1 ") TI_Innovator.Read() if tonumber(rxValue) and tonumber(rxValue) > 0 thenend oneShotTimer(1000,auto) screen:invalidate()TI_Innovator.Send("SET SOUND "..1000*tonumber(rxValue).." 0.1") if tonumber(rxValue) > 0.1 thenendif tonumber(rxValue) > 0.4 thenelsefd(1)elsebk(0.5) rt(0.5)endfd(0) hubStrOff = "ROBOT AUTO OFF" addMsg(hubStrOff) drive = ''end-- 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,476,475,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,476,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,476,440,392,349,330,331,660,587,523,476,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}
In our next lesson, we take these principles and create a more versatile document, which accepts user input into a text field, allowing you to try out variations, and to create your own Innovator hub commands.
Home ← STEM HQ ← TI-Nspire Authoring ← TI-Nspire Scripting HQ ← Scripting Tutorial - Lesson 47