Home ← STEM HQ ← TI-Nspire Authoring ← TI-Nspire Scripting HQ ← Scripting Tutorial - Lesson 46
Scripting Tutorial - Lesson 46: Lua Scripting and the TI Innovator™ Hub:
6. Lua Script for the Norland Research/TI 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 1 for this tutorial: Norland_Robot.tns
Download supporting file 2 for this tutorial: NorlandRobot_TI-BASIC_Sampler.tns
Texas Instruments TI-Nspire Scripting Support Page
Norland Research E3 Innovator Robot Kit
Scripting for the Innovator Hub: Lesson 6: Lua Script for the Norland Research/TI Innovator™ Hub Robot
ANALOG and DIGITAL commandsThe TI Innovator™ Hub has, at its heart, a TI LaunchPad MSP432 micro-controller unit, and every input and output to and from such a unit is really just a matter of sending voltage to a particular pin or set of pins on the board. The Hub offers a wide range of specialised commands for doing everything from setting LEDs and sounds to reading rangers, brightness, accelerometers and more.
However, the Hub command list also includes four generic commands - DIGITAL.IN, DIGITAL.OUT, ANALOG.IN and ANALOG.OUT. These can be used to control any pin to which they are connected and can be very useful as tools for going beyond the basic Hub commands.
For example, the Hub command set includes a SERVO command which is very powerful, and useful for controlling servo motors. The SERVO command includes clockwise and anti-clockwise, speed and time options. Issues associated with SERVO are explored in the next tutorial where we build a home-made Hub robot, but the key issue lies in controlling the current drawn, and not burning out the unprotected board.
The team at Norland Research have chosen a safer and more reliable option for their new Norland Research/TI Innovator™ Hub Robot, using direct current motors rather than servos, and providing their own power supply to ensure that the board is well protected. To control these motors, they use ANALOG and DIGITAL commands.
This robot vehicle is driven by motors controlled by a "H-bridge", allowing two sets of switches to control whether motors run forwards or backwards. In this case, these are controlled by BB pins 1-4, linked to ANALOG.OUT (or DIGITAL.OUT) commands. Using ANALOG.OUT allows the user to specify the speed of the robot; DIGITAL commands are either ON or OFF (0 or 1). Both will work for this device.
BB pins 1-7 are connected from the Hub to the robot - 1-4 control left and right wheels, 5 and 6 link to the bumper at the front of the motor (these are DIGITAL.IN pins), and BB7 reads the robot battery state, using ANALOG.IN.
Whether using TI-BASIC or Lua, the BB pins are connected to their ANALOG or DIGITAL commands, and then these are SET or READ. In this way, the robot can be controlled to move forward, back, left or right.
Below, you will find both simple TI-BASIC programs as well as the full Lua script which may be used to control the Norland Hub robot. 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 Norland Robot TI-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.
![]()
In addition to the usual forward, back, left and right programs, there are simple programs to check the battery level and to check if the front bumpers are activated. There are also two programs related to the Hub's on-board brightness sensor - one which provides easy access to collecting data (which may be plotted or viewed in a spreadsheet) and, more interestingly, a program which uses the surrounding brightness to drive the robot! Entering minimum and maximum brightness values (which might be observed from the previous program), the robot will drive happily until the light is below or above those values - at which points it will reverse and turn to try a new direction!
If the focus is just on using the robot for various purposes OR on more advanced coding, then Lua becomes a clear choice.
Lua offers great opportunities for a simpler interface, controlling the robot by tapping the mouse on a simple control panel, or, even easier for students, simply using the trackpad arrow keys on the handheld to move in the four directions, and escape key to stop.
The Lua script offers the same control features as the TI-BASIC examples, plus other options for drawing on the power of the Hub. You will see from the animated GIF opposite that the autoDrive (or "lightSeeker" program) is a great tool for students to explore both the physical data readings around them, and also important principles of robotics.
Students interested in more challenging coding might be encouraged to explore using sensors other than brightness - an obvious example would be the ultrasonic ranger, with which the robot senses proximity to objects and automatically takes action to avoid these!
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 are 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.
- 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 battcheck()=Prgm
Local A Send "CONNECT ANALOG.IN 7 BB7 " Send "READ ANALOG.IN 7 " Get A Disp A Send "DISCONNECT ANALOG.IN 7 "EndPrgmDefine bumper(time)=Prgm
Local n,l,r Send "CONNECT DIGITAL.IN 5 BB5 " Send "CONNECT DIGITAL.IN 6 BB6 " l:=1 r:=1 For n,1,time Disp "Time "&string(n)&" seconds" Send "READ DIGITAL.IN 5 " Get r Send "READ DIGITAL.IN 6 " Get l If l>0 Then Disp "LEFT BUMP at "&string(n)&" seconds" ElseIf r>0 Then Disp "RIGHT BUMP at "&string(n)&" seconds" EndIf wait 1 EndFor Send "DISCONNECT DIGITAL.IN 5 " Send "DISCONNECT DIGITAL.IN 6 "EndPrgmDefine fd(speed, time)=Prgm
Send "CONNECT ANALOG.OUT 1 BB1 " Send "CONNECT ANALOG.OUT 3 BB3 " Disp "FORWARD" Send "SET ANALOG.OUT 1 "&string(speed) Send "SET ANALOG.OUT 3 "&string(speed) wait time Send "DISCONNECT ANALOG.OUT 1 " Send "DISCONNECT ANALOG.OUT 3 "EndPrgmDefine bk(speed, time)=Prgm
Send "CONNECT ANALOG.OUT 2 BB2 " Send "CONNECT ANALOG.OUT 4 BB4 " Disp "FORWARD" Send "SET ANALOG.OUT 2 "&string(speed) Send "SET ANALOG.OUT 4 "&string(speed) wait time Send "DISCONNECT ANALOG.OUT 2 " Send "DISCONNECT ANALOG.OUT 4 "EndPrgmDefine lt(speed, time)=Prgm
Send "CONNECT ANALOG.OUT 1 BB1 " Send "CONNECT ANALOG.OUT 4 BB4 " Disp "FORWARD" Send "SET ANALOG.OUT 1 "&string(speed) Send "SET ANALOG.OUT 4 "&string(speed) wait time Send "DISCONNECT ANALOG.OUT 1 " Send "DISCONNECT ANALOG.OUT 4 "EndPrgmDefine rt(speed, time)=Prgm
Send "CONNECT ANALOG.OUT 2 BB2 " Send "CONNECT ANALOG.OUT 3 BB3 " Disp "FORWARD" Send "SET ANALOG.OUT 2 "&string(speed) Send "SET ANALOG.OUT 3 "&string(speed) wait time Send "DISCONNECT ANALOG.OUT 2 " Send "DISCONNECT ANALOG.OUT 3 "EndPrgmDefine brightdata(s)=Prgm
Local n,b time:={} brightness:={} For n,1,s Send "READ BRIGHTNESS " Get b time[n]:=n brightness[n]:=b Disp "Brightness "&string(b) Send "SET SOUND eval(b*100) 0.1" Wait 0.1 EndForEndPrgmDefine lightseeker(m,x)=Prgm
Local b b:=0 Send "READ BRIGHTNESS " Get b Disp "Brightness "&string(b) Send "SET SOUND eval(b*10) 0.5" While b>m Send "READ BRIGHTNESS " Get b Disp "Brightness "&string(b) Send "SET SOUND eval(b*10) 0.5" If b>x Then bk(100,1) Else fd(100,0.5) lt(100,0.5) EndIf EndWhileEndPrgm-- TI Innovator Init Values
platform.apilevel = '2.7' local screen = platform.window local date = "060317"
require 'color' pcall(function() require 'asi' end)
local hubStrOn, hubStrOff, msgStr, rxValue, timeStr, bump, repeats, time_step, delay, help local list1, list2, index, dataList = {}, {}, {}, {} var.store("index", index) var.store("dataList", dataList) local fontSize = 20
local robotConnected = false local bump = 0 local orient = var.recall("orient") or 0 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 75 local speedStr = "Robot Speed: "..robotSpeed local autoMin = 5 local autoMax = 20
var.monitor("speed") var.monitor("runtime") var.monitor("time_step") var.monitor("automin") var.monitor("automax") var.monitor("hubstr") var.monitor("orient")
function on.varChange(varList)
orient = var.recall("orient") or 0 robotSpeed = var.recall("speed") or 75 speedStr = "Robot Speed: "..robotSpeed runTime = var.recall("runtime") or 10 runtimeStr = "Run Time: "..runTime time_step = var.recall("time_step") or 0.5 autoMin = var.recall("automin") or 5 autoMax = var.recall("automax") 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(){" ©2017 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",{'Norland Battery Check (b)', function() batteryCheck() end}, {"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 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 DHT 1", function() hubStrOn = "READ DHT 1" TI_Innovator.Send("CONNECT DHT 1 IN1") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() hubStrOff = '' driver = "DHT 1" timeStr = "Press mouse down to take fresh reading" end}, {"READ BAROMETER", function() hubStrOn = "READ BAROMETER" TI_Innovator.Send("CONNECT BAROMETER I2C") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() hubStrOff = '' timeStr = "Press mouse down to take fresh reading" end}, {"READ ACCEL 1", function() hubStrOn = "READ ACCEL 1" TI_Innovator.Send("CONNECT ACCEL 1 I2C") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() hubStrOff = '' timeStr = "Press mouse down to take fresh reading" driver = "ACCEL 1" driverConnected = true 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",{"ROBOT FD runTime", function() fd(runTime) end}, {"ROBOT BK runTime", function() bk(runTime) end}, {"ROBOT LT 1 secs", function() lt(1) end}, {"ROBOT RT 1 secs", function() rt(1) end}, {"autoDrive (a)", function() autoDrive(runTime) end}, {"Switch Handheld Orientation (o)", function() orient = 1 - orient var.store("orient", orient) 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) help, bump, delay, repeats = 0, 0, 0, 1 tempo, key, I = 1000, 0, 1 time_step = var.recall("time_step") or 0.5 runTime = var.recall("runtime") or 10 robotConnected = false 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/25 + 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.25*h, false, true) calcView = calc(0.925*w,0.025*h,0.075*w,0.225*h, false, orient, true) if TI_Innovator.isConnected() thenaddMsg("TI Innovator Hub ready") if not robotConnected then robotConnect() endendfunction on.paint (gc)
gc:setFont("sansserif", "r", fontSize) if TI_Innovator.isConnected() and help == 0 thenendgc:setFont("sansserif", "r", fontSize1) robotControls:paint(gc) gc:setColorRGB (0,255,0) gc:fillRect (0, 0, w, 0.025*h) local sw = gc:getStringWidth(speedStr) gc:drawString(speedStr, 0.9*w - sw, 0.1*h, "middle") local sw = gc:getStringWidth(runtimeStr) gc:drawString(runtimeStr, 0.9*w - sw, 0.2*h, "middle")elsegc:setColorRGB (255,0,0) gc: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,auto min/max) or enter new hub ", 0.025*w, 0.4*h, "middle") gc:drawString("commands using the spreadsheet on the next page", 0.025*w, 0.5*h, "middle") gc:drawString("Tap at top right (or press 'o') to set handheld orientation", 0.025*w, 0.6*h, "middle") gc:drawString("Press b for battery check, a for autoDrive, w for wait (data capture)", 0.025*w, 0.65*h, "middle")end calcView:paint(gc) gc:setFont("sansserif", "r", fontSize) gc:drawString(timeStr, 0.025*w, 0.75*h, "middle") gc:drawString(msgStr, 0.025*w, 0.85*h, "middle") gc:drawString(rxValue, 0.025*w, 0.95*h, "middle") gc:setFont("sansserif", "r", fontSize1) gc:setColorRGB(0, 0, 255) local str = "Norland Hub Robot" local sw = gc:getStringWidth(str) gc:drawString(str, 0.975*w - sw, 0.95*h, "middle")calc = class()
function calc:init(x, y, width, height, selected, orient, visible)
self.x = x self.y = y self.width = width self.height = height self.orient = orient self.visible = visible self.selected = selectedendfunction calc:contains(x, y)
local sw = self.width or self.height local sh = self.height or self.width return x >= self.x and x <= self.x + sw andendy >= self.y and y <= self.y + shfunction calc: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.height gc:setColorRGB(color.black) local str = "bump" local sw = gc:getStringWidth(str) local sh = gc:getStringHeight(str) gc:drawString(str, x + 0.5*width - sw/2, y + 0.1*height + (1-orient)*(height), "middle") gc:setPen("medium", "smooth") gc:drawLine(x + width/2-sw/2, y + (1-orient)*(height + 1.05*sh), x+width/2+sw/2, y + (1-orient)*(height + 1.05*sh)) if self.selected thenendgc:setPen("medium", "smooth")elsegc:setPen("thin", "smooth")end gc:fillRect(x, y + (orient)*1.1*sh, width, height) gc:setColorRGB(color.white) gc:fillRect(x + 0.1*width, y + orient*0.6*height + 0.05*height + (orient)*1.1*sh + (1-orient)*0.6*height, 0.8*width, 0.3*height) gc:setFont("sansserif","r",fontSize1) local str = "calc" local sw = gc:getStringWidth(str) gc:drawString(str, x + 0.5*width - sw/2, y + 0.25*height + 1.1*sh, "middle") gc:setColorRGB(color.black) local verticesUp = {x + 0.5*width, y + orient*0.6*height + 0.1*height + 1.1*sh ,x + 0.75*width, y + orient*0.6*height + 0.275*height + 1.1*sh, x + 0.25*width, y + orient*0.6*height + 0.275*height + 1.1*sh, x + 0.5*width, y + orient*0.6*height + 0.1*height + 1.1*sh,}local verticesDown = {x + 0.5*width, y + orient*0.6*height + 0.275*height + (1-orient)*0.6*height,x + 0.75*width, y + orient*0.6*height + 0.1*height + (1-orient)*0.6*height, x + 0.25*width, y + orient*0.6*height + 0.1*height + (1-orient)*0.6*height, x + 0.5*width, y + orient*0.6*height + 0.275*height + (1-orient)*0.6*height,}if orient > 0 then
gc:fillPolygon(verticesUp)elsegc:fillPolygon(verticesDown)endfunction calc:mouseDown(x, y)
self.selected = true screen:invalidate()endfunction calc:mouseUp(x, y)
orient = 1 - orient var.store("orient",orient) self.selected = false screen:invalidate()endrc = class()
function robotConnect()
pcall(function()endTI_Innovator.Send('BEGIN\n') robotControls.visible = true TI_Innovator.Send("CONNECT ANALOG.OUT 1 BB1") TI_Innovator.Send("CONNECT ANALOG.OUT 2 BB2") TI_Innovator.Send("CONNECT ANALOG.OUT 3 BB3") TI_Innovator.Send("CONNECT ANALOG.OUT 4 BB4") TI_Innovator.Send("CONNECT DIGITAL.IN 5 BB5") TI_Innovator.Send("CONNECT DIGITAL.IN 6 BB6") TI_Innovator.Send("CONNECT ANALOG.IN 7 BB7") robotConnected = true hubStrOn = "" var.store("hubstr", hubStrOn) addMsg("ROBOT ready")end) screen:invalidate()function robotDisconnect()
pcall(function()endTI_Innovator.Send('BEGIN') robotConnected = false hubStrOn = '' hubStrOff = '' bump = 0 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 if orient > 0 then lt(0.5) else rt(0.5) endelseif 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 if orient > 0 then rt(0.5) else lt(0.5) endelseif 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 if orient > 0 then bk(1) else fd(1) endelseif 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 if orient > 0 then fd(1) else bk(1) endelseon.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" thenendif orient > 0 then bk(runTime) else fd(runTime) endelseif key == "up" thenif orient > 0 then fd(runTime) else bk(runTime) endelseif key == "left" thenif orient > 0 then lt(0.5) else rt(0.5) endelseif orient > 0 then rt(0.5) else lt(0.5) endend screen:invalidate()function on.help()
help = 1 - help screen:invalidate()endfunction on.charIn(ch)
if ch == "a" then autoDrive(runTime) elseif ch == "b" then batteryCheck() elseif ch == "o" then orient = 1 - orient var.store("orient",orient) 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.mouseDown(x, y)
if calcView:contains(x, y) thenendcalcView:mouseDown(x, y)end if robotControls.visible and robotControls:contains(x, y) thenrobotControls: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 calcView.selected thenendcalcView:mouseUp(x, y)end if robotControls.visible and robotControls:contains(x, y) thenrobotControls: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") else rxValue = tostring(rxValue) local list = str2list(rxValue,string.char(10)) if list and #list > 0 thenend screen:invalidate()for k = 1, #list doendif tonumber(list[k]) then rxValue = tonumber(list[k]) TI_Innovator.Send("SET SOUND "..100*tonumber(rxValue).." 0.1") break endendfunction 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") TI_Innovator.Send("CONNECT ANALOG.OUT 1 BB1") TI_Innovator.Send("CONNECT ANALOG.OUT 2 BB2") TI_Innovator.Send("CONNECT ANALOG.OUT 3 BB3") TI_Innovator.Send("CONNECT ANALOG.OUT 4 BB4") TI_Innovator.Send("CONNECT DIGITAL.IN 5 BB5") TI_Innovator.Send("CONNECT DIGITAL.IN 6 BB6") TI_Innovator.Send("CONNECT ANALOG.IN 7 BB7") addMsg("ROBOT ready") batteryCheck() 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 batteryCheck()
if not robotConnected then robotConnect() end TI_Innovator.Send('READ ANALOG.IN 7') TI_Innovator.Read() hubStrOn = "READ ANALOG.IN 7" addMsg("READ ANALOG.IN 7") timeStr = "Press mouse to check battery" screen:invalidate()endfunction bumpCheck(time)
if not robotConnected then robotConnect() end if math.floor(time) == time thenendTI_Innovator.Send('READ DIGITAL.IN 5') TI_Innovator.Read() if tonumber(rxValue) then bump = bump + math.abs(tonumber(rxValue)) endelseTI_Innovator.Send('READ DIGITAL.IN 6') TI_Innovator.Read() if tonumber(rxValue) then bump = bump + math.abs(tonumber(rxValue)) endend screen:invalidate() return bumpfunction fd(input)
if not robotConnected then robotConnect() end if input then delay = input end bump = bumpCheck(delay) if bump == 0 and delay >= 0 thenendaddMsg("ROBOT FORWARD") TI_Innovator.Send('SET ANALOG.OUT 1 '..robotSpeed) TI_Innovator.Send('SET ANALOG.OUT 3 '..robotSpeed) timeStr = delay.." seconds" delay = delay - time_step oneShotTimer(1000*time_step,fd)elseTI_Innovator.Send('SET ANALOG.OUT 1 0') TI_Innovator.Send('SET ANALOG.OUT 3 0') addMsg('') if bump < 0 then addMsg("Left bumper alert!") elseif bump > 0 then addMsg("Right bumper alert!") end bump = 0 delay = 0end screen:invalidate()function bk(input)
if not robotConnected then robotConnect() end if input then delay = input end bump = bumpCheck(delay) if bump == 0 and delay >= 0 thenendaddMsg("ROBOT BACK") TI_Innovator.Send('SET ANALOG.OUT 2 '..robotSpeed) TI_Innovator.Send('SET ANALOG.OUT 4 '..robotSpeed) timeStr = delay.." seconds" delay = delay - time_step oneShotTimer(1000*time_step,bk)elseTI_Innovator.Send('SET ANALOG.OUT 2 0') TI_Innovator.Send('SET ANALOG.OUT 4 0') addMsg('') if bump < 0 then addMsg("Left bumper alert!") elseif bump > 0 then addMsg("Right bumper alert!") end bump = 0 delay = 0end screen:invalidate()function lt(input)
if not robotConnected then robotConnect() end if input then delay = input end bump = bumpCheck(delay) if bump == 0 and delay >= 0 thenendaddMsg("ROBOT LEFT") TI_Innovator.Send('SET ANALOG.OUT 1 '..robotSpeed) TI_Innovator.Send('SET ANALOG.OUT 4 '..robotSpeed) timeStr = delay.." seconds" delay = delay - time_step oneShotTimer(1000*time_step,lt)elseTI_Innovator.Send('SET ANALOG.OUT 1 0') TI_Innovator.Send('SET ANALOG.OUT 4 0') addMsg('') if bump < 0 then addMsg("Left bumper alert!") elseif bump > 0 then addMsg("Right bumper alert!") end bump = 0 delay = 0end screen:invalidate()function rt(input)
if not robotConnected then robotConnect() end if input then delay = input end bump = bumpCheck(delay) if bump == 0 and delay >= 0 thenendaddMsg("ROBOT RIGHT") TI_Innovator.Send('SET ANALOG.OUT 2 '..robotSpeed) TI_Innovator.Send('SET ANALOG.OUT 3 '..robotSpeed) timeStr = delay.." seconds" delay = delay - time_step oneShotTimer(1000*time_step,rt)elseTI_Innovator.Send('SET ANALOG.OUT 2 0') TI_Innovator.Send('SET ANALOG.OUT 3 0') addMsg('') if bump < 0 then addMsg("Left bumper alert!") elseif bump > 0 then addMsg("Right bumper alert!") end bump = 0 delay = 0end screen:invalidate()function autoDrive(input)
if not robotConnected then robotConnect() end if input then delay = input end if delay >= 0 thenTI_Innovator.Send("READ BRIGHTNESS") TI_Innovator.Read() if tonumber(rxValue) and tonumber(rxValue) > tonumber(autoMin)/2 thenendif tonumber(rxValue) > tonumber(autoMin) and tonumber(rxValue) < tonumber(autoMax) thenendTI_Innovator.Send('SET ANALOG.OUT 1 0') TI_Innovator.Send('SET ANALOG.OUT 3 0') TI_Innovator.Send('SET ANALOG.OUT 2 '..robotSpeed) TI_Innovator.Send('SET ANALOG.OUT 4 '..robotSpeed) addMsg("ROBOT BACK")elseTI_Innovator.Send('SET ANALOG.OUT 2 0') TI_Innovator.Send('SET ANALOG.OUT 4 0') TI_Innovator.Send('SET ANALOG.OUT 1 '..robotSpeed) TI_Innovator.Send('SET ANALOG.OUT 3 '..robotSpeed) addMsg("ROBOT FORWARD" ) TI_Innovator.Send('SET ANALOG.OUT 1 0') TI_Innovator.Send('SET ANALOG.OUT 4 0') TI_Innovator.Send('SET ANALOG.OUT 2 '..robotSpeed) TI_Innovator.Send('SET ANALOG.OUT 3 '..robotSpeed) addMsg("ROBOT RIGHT")endtimeStr = delay.." seconds" delay = delay - time_step oneShotTimer(1000*time_step,autoDrive)elseaddMsg('') TI_Innovator.Send('SET ANALOG.OUT 1 0') TI_Innovator.Send('SET ANALOG.OUT 2 0') TI_Innovator.Send('SET ANALOG.OUT 3 0') TI_Innovator.Send('SET ANALOG.OUT 4 0')end 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 = "060317"
require 'color' pcall(function() require 'asi' end)
local hubStrOn, hubStrOff, msgStr, rxValue, timeStr, bump, repeats, time_step, delay, help local list1, list2, index, dataList = {}, {}, {}, {} var.store("index", index) var.store("dataList", dataList) local fontSize = 20
local robotConnected = false local bump = 0 local orient = var.recall("orient") or 0 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 75 local speedStr = "Robot Speed: "..robotSpeed local autoMin = 5 local autoMax = 20
var.monitor("speed") var.monitor("runtime") var.monitor("time_step") var.monitor("automin") var.monitor("automax") var.monitor("hubstr") var.monitor("orient")
function on.varChange(varList)
orient = var.recall("orient") or 0 robotSpeed = var.recall("speed") or 75 speedStr = "Robot Speed: "..robotSpeed runTime = var.recall("runtime") or 10 runtimeStr = "Run Time: "..runTime time_step = var.recall("time_step") or 0.5 autoMin = var.recall("automin") or 5 autoMax = var.recall("automax") or 20 hubStrOn = string.upper(var.recall("hubstr")) or '' if hubStrOn:find("ON") thenendhubStrOff = hubStrOn:gsub("ON","OFF")elsehubStrOff = ''end screen:invalidate()function addMsg(input)
msgStr = input print(msgStr) screen:invalidate()end
function on.construction()
end--the next three lines are required for Hub connection TI_Innovator.init(TI_InnovatorStateCallback) TI_Innovator.setReadListener(TI_InnovatorReadCallback) TI_Innovator.connect()
Menu={
{"About",} toolpalette.register(Menu) screen:invalidate(){" ©2017 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",{'Norland Battery Check (b)', function() batteryCheck() end}, {"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 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 DHT 1", function() hubStrOn = "READ DHT 1" TI_Innovator.Send("CONNECT DHT 1 IN1") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() hubStrOff = '' driver = "DHT 1" timeStr = "Press mouse down to take fresh reading" end}, {"READ BAROMETER", function() hubStrOn = "READ BAROMETER" TI_Innovator.Send("CONNECT BAROMETER I2C") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() hubStrOff = '' timeStr = "Press mouse down to take fresh reading" end}, {"READ ACCEL 1", function() hubStrOn = "READ ACCEL 1" TI_Innovator.Send("CONNECT ACCEL 1 I2C") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() hubStrOff = '' timeStr = "Press mouse down to take fresh reading" driver = "ACCEL 1" driverConnected = true 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",{"ROBOT FD runTime", function() fd(runTime) end}, {"ROBOT BK runTime", function() bk(runTime) end}, {"ROBOT LT 1 secs", function() lt(1) end}, {"ROBOT RT 1 secs", function() rt(1) end}, {"autoDrive (a)", function() autoDrive(runTime) end}, {"Switch Handheld Orientation (o)", function() orient = 1 - orient var.store("orient", orient) 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) help, bump, delay, repeats = 0, 0, 0, 1 tempo, key, I = 1000, 0, 1 time_step = var.recall("time_step") or 0.5 runTime = var.recall("runtime") or 10 robotConnected = false 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/25 + 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.25*h, false, true) calcView = calc(0.925*w,0.025*h,0.075*w,0.225*h, false, orient, true) if TI_Innovator.isConnected() thenaddMsg("TI Innovator Hub ready") if not robotConnected then robotConnect() endendfunction on.paint (gc)
gc:setFont("sansserif", "r", fontSize) if TI_Innovator.isConnected() and help == 0 thenendgc:setFont("sansserif", "r", fontSize1) robotControls:paint(gc) gc:setColorRGB (0,255,0) gc:fillRect (0, 0, w, 0.025*h) local sw = gc:getStringWidth(speedStr) gc:drawString(speedStr, 0.9*w - sw, 0.1*h, "middle") local sw = gc:getStringWidth(runtimeStr) gc:drawString(runtimeStr, 0.9*w - sw, 0.2*h, "middle")elsegc:setColorRGB (255,0,0) gc: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,auto min/max) or enter new hub ", 0.025*w, 0.4*h, "middle") gc:drawString("commands using the spreadsheet on the next page", 0.025*w, 0.5*h, "middle") gc:drawString("Tap at top right (or press 'o') to set handheld orientation", 0.025*w, 0.6*h, "middle") gc:drawString("Press b for battery check, a for autoDrive, w for wait (data capture)", 0.025*w, 0.65*h, "middle")end calcView:paint(gc) gc:setFont("sansserif", "r", fontSize) gc:drawString(timeStr, 0.025*w, 0.75*h, "middle") gc:drawString(msgStr, 0.025*w, 0.85*h, "middle") gc:drawString(rxValue, 0.025*w, 0.95*h, "middle") gc:setFont("sansserif", "r", fontSize1) gc:setColorRGB(0, 0, 255) local str = "Norland Hub Robot" local sw = gc:getStringWidth(str) gc:drawString(str, 0.975*w - sw, 0.95*h, "middle")calc = class()
function calc:init(x, y, width, height, selected, orient, visible)
self.x = x self.y = y self.width = width self.height = height self.orient = orient self.visible = visible self.selected = selectedendfunction calc:contains(x, y)
local sw = self.width or self.height local sh = self.height or self.width return x >= self.x and x <= self.x + sw andendy >= self.y and y <= self.y + shfunction calc: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.height gc:setColorRGB(color.black) local str = "bump" local sw = gc:getStringWidth(str) local sh = gc:getStringHeight(str) gc:drawString(str, x + 0.5*width - sw/2, y + 0.1*height + (1-orient)*(height), "middle") gc:setPen("medium", "smooth") gc:drawLine(x + width/2-sw/2, y + (1-orient)*(height + 1.05*sh), x+width/2+sw/2, y + (1-orient)*(height + 1.05*sh)) if self.selected thenendgc:setPen("medium", "smooth")elsegc:setPen("thin", "smooth")end gc:fillRect(x, y + (orient)*1.1*sh, width, height) gc:setColorRGB(color.white) gc:fillRect(x + 0.1*width, y + orient*0.6*height + 0.05*height + (orient)*1.1*sh + (1-orient)*0.6*height, 0.8*width, 0.3*height) gc:setFont("sansserif","r",fontSize1) local str = "calc" local sw = gc:getStringWidth(str) gc:drawString(str, x + 0.5*width - sw/2, y + 0.25*height + 1.1*sh, "middle") gc:setColorRGB(color.black) local verticesUp = {x + 0.5*width, y + orient*0.6*height + 0.1*height + 1.1*sh ,x + 0.75*width, y + orient*0.6*height + 0.275*height + 1.1*sh, x + 0.25*width, y + orient*0.6*height + 0.275*height + 1.1*sh, x + 0.5*width, y + orient*0.6*height + 0.1*height + 1.1*sh,}local verticesDown = {x + 0.5*width, y + orient*0.6*height + 0.275*height + (1-orient)*0.6*height,x + 0.75*width, y + orient*0.6*height + 0.1*height + (1-orient)*0.6*height, x + 0.25*width, y + orient*0.6*height + 0.1*height + (1-orient)*0.6*height, x + 0.5*width, y + orient*0.6*height + 0.275*height + (1-orient)*0.6*height,}if orient > 0 then
gc:fillPolygon(verticesUp)elsegc:fillPolygon(verticesDown)endfunction calc:mouseDown(x, y)
self.selected = true screen:invalidate()endfunction calc:mouseUp(x, y)
orient = 1 - orient var.store("orient",orient) self.selected = false screen:invalidate()endrc = class()
function robotConnect()
pcall(function()endTI_Innovator.Send('BEGIN\n') robotControls.visible = true TI_Innovator.Send("CONNECT ANALOG.OUT 1 BB1") TI_Innovator.Send("CONNECT ANALOG.OUT 2 BB2") TI_Innovator.Send("CONNECT ANALOG.OUT 3 BB3") TI_Innovator.Send("CONNECT ANALOG.OUT 4 BB4") TI_Innovator.Send("CONNECT DIGITAL.IN 5 BB5") TI_Innovator.Send("CONNECT DIGITAL.IN 6 BB6") TI_Innovator.Send("CONNECT ANALOG.IN 7 BB7") robotConnected = true hubStrOn = "" var.store("hubstr", hubStrOn) addMsg("ROBOT ready")end) screen:invalidate()function robotDisconnect()
pcall(function()endTI_Innovator.Send('BEGIN') robotConnected = false hubStrOn = '' hubStrOff = '' bump = 0 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 if orient > 0 then lt(0.5) else rt(0.5) endelseif 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 if orient > 0 then rt(0.5) else lt(0.5) endelseif 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 if orient > 0 then bk(1) else fd(1) endelseif 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 if orient > 0 then fd(1) else bk(1) endelseon.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" thenendif orient > 0 then bk(runTime) else fd(runTime) endelseif key == "up" thenif orient > 0 then fd(runTime) else bk(runTime) endelseif key == "left" thenif orient > 0 then lt(0.5) else rt(0.5) endelseif orient > 0 then rt(0.5) else lt(0.5) endend screen:invalidate()function on.help()
help = 1 - help screen:invalidate()endfunction on.charIn(ch)
if ch == "a" then autoDrive(runTime) elseif ch == "b" then batteryCheck() elseif ch == "o" then orient = 1 - orient var.store("orient",orient) 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.mouseDown(x, y)
if calcView:contains(x, y) thenendcalcView:mouseDown(x, y)end if robotControls.visible and robotControls:contains(x, y) thenrobotControls: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 calcView.selected thenendcalcView:mouseUp(x, y)end if robotControls.visible and robotControls:contains(x, y) thenrobotControls: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") else rxValue = tostring(rxValue) local list = str2list(rxValue,string.char(10)) if list and #list > 0 thenend screen:invalidate()for k = 1, #list doendif tonumber(list[k]) then rxValue = tonumber(list[k]) TI_Innovator.Send("SET SOUND "..100*tonumber(rxValue).." 0.1") break endendfunction 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") TI_Innovator.Send("CONNECT ANALOG.OUT 1 BB1") TI_Innovator.Send("CONNECT ANALOG.OUT 2 BB2") TI_Innovator.Send("CONNECT ANALOG.OUT 3 BB3") TI_Innovator.Send("CONNECT ANALOG.OUT 4 BB4") TI_Innovator.Send("CONNECT DIGITAL.IN 5 BB5") TI_Innovator.Send("CONNECT DIGITAL.IN 6 BB6") TI_Innovator.Send("CONNECT ANALOG.IN 7 BB7") batteryCheck() addMsg("ROBOT ready") 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 var.store("hubstr", hubStrOn) addMsg(hubStrOn) TI_Innovator.Send(hubStrOn) TI_Innovator.Send(str) oneShotTimer((tempo/list2[I])+20, waitTone) I = I + 1endhubStrOn = "" hubStrOff = "" addMsg(hubStrOff)endfunction playTone(list1, list2)
waitTone() screen:invalidate()end-- ROBOT COMMANDS BEGIN
function batteryCheck()
if not robotConnected then robotConnect() end TI_Innovator.Send('READ ANALOG.IN 7') TI_Innovator.Read() hubStrOn = "READ ANALOG.IN 7" addMsg("READ ANALOG.IN 7") timeStr = "Press mouse to check battery" screen:invalidate()endfunction bumpCheck(time)
if not robotConnected then robotConnect() end if math.floor(time) == time thenendTI_Innovator.Send('READ DIGITAL.IN 5') TI_Innovator.Read() if tonumber(rxValue) then bump = bump + math.abs(tonumber(rxValue)) endelseTI_Innovator.Send('READ DIGITAL.IN 6') TI_Innovator.Read() if tonumber(rxValue) then bump = bump + math.abs(tonumber(rxValue)) endend screen:invalidate() return bumpfunction fd(input)
if not robotConnected then robotConnect() end if input then delay = input end bump = bumpCheck(delay) if bump == 0 and delay >= 0 thenendaddMsg("ROBOT FORWARD") TI_Innovator.Send('SET ANALOG.OUT 1 '..robotSpeed) TI_Innovator.Send('SET ANALOG.OUT 3 '..robotSpeed) timeStr = delay.." seconds" delay = delay - time_step oneShotTimer(1000*time_step,fd)elseTI_Innovator.Send('SET ANALOG.OUT 1 0') TI_Innovator.Send('SET ANALOG.OUT 3 0') addMsg('') if bump < 0 then addMsg("Left bumper alert!") elseif bump > 0 then addMsg("Right bumper alert!") end bump = 0 delay = 0end screen:invalidate()function bk(input)
if not robotConnected then robotConnect() end if input then delay = input end bump = bumpCheck(delay) if bump == 0 and delay >= 0 thenendaddMsg("ROBOT BACK") TI_Innovator.Send('SET ANALOG.OUT 2 '..robotSpeed) TI_Innovator.Send('SET ANALOG.OUT 4 '..robotSpeed) timeStr = delay.." seconds" delay = delay - time_step oneShotTimer(1000*time_step,bk)elseTI_Innovator.Send('SET ANALOG.OUT 2 0') TI_Innovator.Send('SET ANALOG.OUT 4 0') addMsg('') if bump < 0 then addMsg("Left bumper alert!") elseif bump > 0 then addMsg("Right bumper alert!") end bump = 0 delay = 0end screen:invalidate()function lt(input)
if not robotConnected then robotConnect() end if input then delay = input end bump = bumpCheck(delay) if bump == 0 and delay >= 0 thenendaddMsg("ROBOT LEFT") TI_Innovator.Send('SET ANALOG.OUT 1 '..robotSpeed) TI_Innovator.Send('SET ANALOG.OUT 4 '..robotSpeed) timeStr = delay.." seconds" delay = delay - time_step oneShotTimer(1000*time_step,lt)elseTI_Innovator.Send('SET ANALOG.OUT 1 0') TI_Innovator.Send('SET ANALOG.OUT 4 0') addMsg('') if bump < 0 then addMsg("Left bumper alert!") elseif bump > 0 then addMsg("Right bumper alert!") end bump = 0 delay = 0end screen:invalidate()function rt(input)
if not robotConnected then robotConnect() end if input then delay = input end bump = bumpCheck(delay) if bump == 0 and delay >= 0 thenendaddMsg("ROBOT RIGHT") TI_Innovator.Send('SET ANALOG.OUT 2 '..robotSpeed) TI_Innovator.Send('SET ANALOG.OUT 3 '..robotSpeed) timeStr = delay.." seconds" delay = delay - time_step oneShotTimer(1000*time_step,rt)elseTI_Innovator.Send('SET ANALOG.OUT 2 0') TI_Innovator.Send('SET ANALOG.OUT 3 0') addMsg('') if bump < 0 then addMsg("Left bumper alert!") elseif bump > 0 then addMsg("Right bumper alert!") end bump = 0 delay = 0end screen:invalidate()function autoDrive(input)
if not robotConnected then robotConnect() end if input then delay = input end if delay >= 0 thenTI_Innovator.Send("READ BRIGHTNESS") TI_Innovator.Read() if tonumber(rxValue) and tonumber(rxValue) > tonumber(autoMin)/2 thenendif tonumber(rxValue) > tonumber(autoMin) and tonumber(rxValue) < tonumber(autoMax) thenendTI_Innovator.Send('SET ANALOG.OUT 1 0') TI_Innovator.Send('SET ANALOG.OUT 3 0') TI_Innovator.Send('SET ANALOG.OUT 2 '..robotSpeed) TI_Innovator.Send('SET ANALOG.OUT 4 '..robotSpeed) addMsg("ROBOT BACK")elseTI_Innovator.Send('SET ANALOG.OUT 2 0') TI_Innovator.Send('SET ANALOG.OUT 4 0') TI_Innovator.Send('SET ANALOG.OUT 1 '..robotSpeed) TI_Innovator.Send('SET ANALOG.OUT 3 '..robotSpeed) addMsg("ROBOT FORWARD" ) TI_Innovator.Send('SET ANALOG.OUT 1 0') TI_Innovator.Send('SET ANALOG.OUT 4 0') TI_Innovator.Send('SET ANALOG.OUT 2 '..robotSpeed) TI_Innovator.Send('SET ANALOG.OUT 3 '..robotSpeed) addMsg("ROBOT RIGHT")endtimeStr = delay.." seconds" delay = delay - time_step oneShotTimer(1000*time_step,autoDrive)elseaddMsg('') TI_Innovator.Send('SET ANALOG.OUT 1 0') TI_Innovator.Send('SET ANALOG.OUT 2 0') TI_Innovator.Send('SET ANALOG.OUT 3 0') TI_Innovator.Send('SET ANALOG.OUT 4 0')end 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}
------------------------------------------------------------------------
In our next lesson, we take these ideas further and build our own simple robot, exploring the servo commands.
Home ← STEM HQ ← TI-Nspire Authoring ← TI-Nspire Scripting HQ ← Scripting Tutorial - Lesson 46