Thymio, barcode reader
How to use the code
Requirements:
- a Thymio II
- Aseba Studio
- a micro-SD card (note: while the site does list some conditions, users have reported other cards working despite not conforming to them. take this as you will)
- an adaptator, if your computer doesn't have a port for micro-SD
- wav mono sound files under 8000hz, without metadata, encoded “unsigned 8 bit PCM”
- a printer, or a sheet of paper and a black pen (not every ink works. if your ink reflects too much ir light, Thymio won't be able to recognize it. to avoid this, prefer carbon black ink.)
Name each of your audio files “px”, x being a value between 0 and 32767. Place them at the root of your micro-SD card, and then insert it in Thymio. Plug Thymio to your computer, open Aseba Studio, and open the code. Edit the call sound.play(x)
lines under #— execution
and replace x with the name of the value you chose for your wav files (example: if your file is named “p16”, write call sound.play(16)
). Then, run the code.
Next, you need a sheet of paper with some black lines drawn on. Note that each line and each space between the lines must be minimum 0,5mm and maximum 9cm wide, and minimum 8cm long. Different notes are registered every 0,5mm, and it may read a total of 20 notes. This may be edited in the code, but keep the motor speeds low. If Thymio moves any faster, it can't keep up as well, and gives false values.
How does it work
Specifications
#this code reads barcodes based on bar width #speed = 0,5 cm/s ; max 20 notes ; different note every 0,5 cm ; 9 different notes ; min width 0,5 cm ; max width 9cm ; min length 5 cm but 8 recommended ; ink must absorb ir light (carbon black) #prioritize the bars to be too big rather than too small (for example, if a bar should be 3cm; 3,4cm > 2,9cm). in fact, do make them a millimeter or two wider
These are just specifications, conditions for the code to work as intended and limitations. Disregard “max 40 notes” in the original code, its maximum is 20, I just got myself mixed up.
Setup
#----- var state = 0 var counter = 0 var deque[2+(1*40)] var n var note var pause timer.period[0]=500 #half a second
Here, I'm setting my variables and the timer.
Technically, deque1) could've just been set by writing var deque[42]
, but for better legibility, 2 represents the two elements in the deque that serve to count what's inside, and “1*40” means that I can store 40 tuples of 1 element each.
Buttons
#----- onevent button.center if button.center == 1 then state = 1 end onevent button.forward #skip straight to playing sounds if impatient if button.forward == 1 and state == 1 then state = 3 end
If you've downloaded the code, you'll notice this part is actually at the end. It doesn't matter much, though, it's gonna be read the same way if it's before or after, I just thought it'd be more understandable if I put it at the start here.
onevent button.center
means that on the event that button.center is updated, or in other words, when it is pressed, then the following plays. In this case, it sets the state variable to 1 when the center button is pressed.
if button.forward == 1 and state == 1
, I added this so that it's possible to skip waiting for Thymio to realize that there aren't any more black lines to read.
onevent timer0 and state 1
#----- onevent timer0 counter++ #--- "white state" if state == 1 then call leds.top(0,0,32) motor.right.target = 25 motor.left.target = 25 if prox.ground.delta[0] < 700 or prox.ground.delta[1] < 700 then call deque.push_back(deque, counter) state = 2 counter = 0 else if counter > 15 then state = 3 end end end
With the line onevent timer0
, I'm telling it to repeat everything that's written underneath every 500ms. Then, we have counter++
, which adds 1 to counter every time it reads it : so in this case, that's every 500ms. This is how I count how long something has lasted for.
As stated above, state is equal to 1 when the center button is pressed. if state == 1
, now it's going to read this part of the code and ignore everything else that only plays when state is equal to anything but 1. I set the top lights to light up in blue, and both motors to move at a speed of 25 each (which is approximately 1 centimeter per second).
if prox.ground.delta[0] < 700 or prox.ground.delta[1] < 700 then
if one or the other ground proximity sensors of Thymio's value2) is under 700, then call deque.push_back(deque, counter)
. This means that the value of counter, at the time of reading this, is put at the end of the deque. In other words, the time spent from not seeing a black bar to seeing one is placed as an element in the deque so that we can use it later.
state = 2
and counter = 0
sets state to 2 and counter to 0.
else if counter > 15 then
if neither of the proximity sensors are under 700 and the value of counter is above 15 (15*500ms, so 7,5 seconds), then we assume that there's no black bars to read down the line, and we set state to 3
state 2 and 3
#--- "black state" if state == 2 then call leds.top(32,0,0) if prox.ground.delta[0] > 900 or prox.ground.delta[1] > 900 then call deque.push_back(deque, counter) state = 1 counter = 0 end end #--- transition, check if empty if state == 3 then call sound.play(-1) call leds.top(0,0,0) motor.right.target = 0 motor.left.target = 0 call deque.size(deque, n) if n == 0 then state = 0 else state = 4 counter = 0 end call deque.pop_front(deque, (pause/2)) end
if state == 2 then
if state is equal to 2, it lights the leds up in red. Then, it checks if the ground proximity sensors have a value above 900 this time, in which case we assume it means that it's seeing white. We push the value of counter at the end of the deque again and set state back to 1, so that the previous code can be read again, and it can look for more black lines.
So, it's gotta keep repeating those two states until there's no more black lines to read.
After that, we have state 3. As stated above, state is equal to 3 when Thymio hasn't encountered a black line in more than 7,5 seconds. The leds turn off and the motors stop moving.
call sound.play(-1)
makes thymio stop playing sound. call deque.size(deque, n)
checks how many elements are in the deque, then sets n to that value. if n is equal to 0, that means there's nothing in the deque, and we set state to 0; if there's nothing in the deque there's nothing to play and we can stop requesting anything from Thymio. else
if it's not 0, then we set state to 4, and counter to 0.
call deque.pop_front(deque, (pause/2))
pop the first element of deque and set pause to that, then divide it by 2. That first element was the time it took to meet a black line. “pop” means to copy that element and then delete it.
state 4
#--- execution if state == 4 then if counter == pause then call deque.pop_front(deque, note) if note <= 1 then call sound.play(11) call leds.top(31,1,1) end if note == 2 then call sound.play(12) call leds.top(32,5,0) end if note == 3 then call sound.play(13) call leds.top(0,32,5) end if note == 4 then call sound.play(14) call leds.top(32,0,0) end if note == 5 then call sound.play(15) call leds.top(25,5,7) end if note == 6 then call sound.play(16) call leds.top(32,0,0) end if note == 7 then call sound.play(17) call leds.top(0,32,10) end if note == 8 then call sound.play(18) call leds.top(32,32,10) end if note == 9 then call sound.play(19) call leds.top(30,10,20) end if note == 10 then call sound.play(110) call leds.top(20,10,10) end if note == 11 then call sound.play(111) call leds.top(5,20,10) end if note == 12 then call sound.play(112) call leds.top(15,10,5) end if note == 13 then call sound.play(113) call leds.top(12,0,31) end if note == 14 then call sound.play(114) call leds.top(31,28,2) end if note >= 15 then call sound.play(115) call leds.top(2,32,4) end end if counter == 1 then state = 3 end end
if counter == pause then
if counter is equal to pause, then call deque.pop_front(deque, note)
pop the first element of deque again and set note to that. That element was the time it took Thymio to reach the end of a black bar.
if note == x then
, call sound.play(x)
play a sound corresponding to each note. The sound is saved on a micro-sd card and inserted in the Thymio.
if counter == 1 then
, state = 3
set state to 3 when half a second has passed, so that it can repeat until n is equal to 0 (until there's nothing in the deque anymore)