2015-01-10

Counter 4 strele.lt


   Atsirado daug maž realus poreikis įsigyti RaspberryPI, o tiksliau sakant BananaPI, kuris yra šiek tiek daugiau "prodvinutas". Daugiau RAM`o, 2 corai, integruotas IR ir panašiai. Kolegos lankininkai užsiminė apie skaitliuką kuris visai praverstų mūsų klube, Mūsų klubas nėra toks labai apsisprendęs todėl šaudo su tuo ką turi. Yra taip vadinamų žemdirbių (longbow), yra olimpinių, nemažai ir dviratininkų (compound). Vienas kitas atsiranda ir su istoriniais lankais. Visa bėda tame, kad žemdirbiai savo strėles iššaudo vos ne per 30 sekundžių, tuo tarpu kaip dviratininkai buna iššovę dar tik savo pirmąją. Kai dauguma baigia visi einam išsitraukt strėlių. Taigi arba vieni arba kiti būna nuskriausti. O kai ateina varžybos, dažniausiai dviratukininkai jaušia diskomfortą, nęs per treniruotes jiems retai kada tenka paleisti į strėlių seriją. Po pirmo roundo visi jaučiasi gerokai paplušėję. Kas galiausiai įtakoja ir rezultatus.
   Taigi nusprendėm, kad mums neprošalį būtų nepriklausomas arbitras, kuris reguliuotų laiką. Bandėm ieškot internete, bet kainos nežmoniškos, o ir funkcionalumas toks abejotinas. Tada kažkaip sušvietė jog galima pasigamint patiem. Apgalvojau Arduino panaudojimo galimybes, eilinio PC, bet galiausiai apsistojau prie RaspberriPI. Tai bene paprasčiausia programavimo terpė, o taip pat ir galimybių pasirinkimas. Na kaina gal ir didoka gaunasi, bet žvelgiant į ateitį, tą patį įrenginį galima panaudoti ir kitiems tikslams. Taigi BananaPI iš aliexpress.com kainavo 43$, kabelis iš HDMI į VGA 6$, kortelė 4Gb 9$, dėžutė bananui beveik 8$, monitorių turėjau seną praktiškai nenaudojamą žinoma kažkiek irgi reiktų įvertinti. Alio.lt šiuo metu galima rasti tokį apie 100Lt. (oi dabar jau eurai :) taigi apie 30E.

   Kaip ir visada prasideda apetitas atsiranda nevalgant. Vien skaitliuko nepakanka, reikia ir garsinio signalo. Atsirado ir indeksų poreikis. Čia tam atvejui jei visi šauliai netelpa į salę ir šaudo pakaitomis. Poto kad nebūtų nuobodu prireikė muzikos. Poto sumastėm jog muzika treniruočių metu muzika turi groti visada, o per varžybas tik tuomet kai einam susirinkti strėlių. Aišku per varžybas būtų gerai matyti ir kelintą seriją jau sušaudėm. Bijau kad dar teks padirbėt  prie indeksų nes per varšybas jie kaitaliojami, kad kuo labiau suvienodinti šaulių sąlygas.  Šauliai keičiasi taikiniais tarp roundų (šitą taip pat reiks "pridevelopint", o taip pat keičiasi ir eiliškumu tarp serijų. Jei šaudoma 2 indeksais tai eiliškumas būna tiks: 
1. A šauliai paleidžia seriją iš 5 strėlių.
2. Tada B šauliai paleidžia seriją iš 5 strėlių.
3. Einam skaičiuot taškų ir susirinkt strėlių.
4. Dabar jau šauna B šauliai savo seriją
5. Ir tik poto A šauliai.
6. Vėl sisi susirenkam savo šmutkes
7. Dabar viskas iš pradžių A
8. Poto B
9. skaičiuojam
10. B
11. ir vėl A
12. Skaičiuojam ir baigiam roundą.

13. Pradedam II roundą. Taigi dabar šauna B indexsai, beto keičiasi taikiniais. Tie kas šovė į viršų šauna į apačią ir atvirkščiai.
14. Ir t.t.

Taigi algoritmas toks komplikuotas. O kai atsiranda 3 indeksai - visai įdomu :D

   Na gana čia apie šitą ritualą. Norėjau parodytį patį tvarinį. Instaliavau Bananian distribuciją. papildomai sudėjau garso ALSA draiverius (vėliau gal aprašysiu detaliau), python su visokiais pribambasais, ir X windows, kad būt gražiau. Beto išjungiau networką nes jis kaip ir nereikalingas bus, o be to dhcp labai jau ilgai ne timeout`ina. Valdymą pasirinkau per IR nes klaviatūra gal ir lankstesnis, bet tuo patčiu bus per sudėtingas dalykas vartotojui. Taigi paėmiau pigų pultelį (vienas šaulys paaukojo :))



   Kaip nekeista, bet labiausiai prasikankinau su built-in IR draiveriu (sunxi-ir) kurio key-mapingnas taip pat įhardkodintas į kernelį. taigi teko iškreiptu būdu mapinti klavišus kurie visiškai neatitiko to kas pavaizduota pultelyje. Čia didžiausias pagalbininkas buvo evtest toolsas, kurias labai gražiai pasako ką ten maigai ant pulto :) Nes tokių klavišy kaip F9 ar Control praktiškai nepamatysi konsolėje.
   Taigi papildomai teko pakeist keletą config failų:
/etc/rc.local
/etc/alsa.conf
/etc/network/interfaces

   Viską rašiau pythonu, nes kaip tik dabar kartais tenka jį pamaigyt, tai nusprendžiau, kad čia bus nebloga praktika. Poto, kai sumastėm, kad reikia muzikos, patingėjau krauti python`o bibliotekas todėl panaudojaum "mocp" ("music on console" ar kažkas panašaus), o garso valdymui taip pat naudojau "amixer" consolinę utėlę. Taigi startui ir stopui parašiau pora ksh scriptukų.

#config
volmin=40
volnorm=80
volmax=100
dir=/mnt
delay=0 # cia jei chebra uzsimanys kazkiek tylos pries alarma
wf=/root/c

fadeout () {
  i=$volnorm
  while [ $i -ge $volmin ]
  do
 let $((i--))
 amixer set 'Master' ${i}%>/dev/null 2>&1
 sleep 0.01
  done
}

fadein () {
  i=$volmin
  while [ $i -le $volnorm ]
  do
 let $((i++))
 amixer set 'Master' ${i}%>/dev/null 2>&1
 sleep 0.01
  done
}

#start
#!/usr/bin/ksh
. /root/c/config
[ -f $wf/mp3_found ] && fadeout && mocp -M $wf/.moc1 -P
sleep 0.2
sleep $delay
amixer set 'Master' ${volmax}% >/dev/null 2>&1

mocp -M $wf/.moc2 -l $wf/w/start.mp3 >/dev/null 2>&1
sleep 1
mocp -M $wf/.moc2 -l $wf/w/start.mp3 >/dev/null 2>&1
sleep 1
amixer set 'Master' ${volmin}% >/dev/null 2>&1

[ -f $wf/mp3_found ] &&  [ -f $wf/mp3_play ] && mocp -M $wf/.moc1 -U && fadein &

#stop
#!/usr/bin/ksh 
. /root/c/config

[ -f $wf/mp3_found ] &&  mocp -M $wf/.moc1 -P
sleep 0.2
amixer set 'Master' ${volmax}% >/dev/null 2>&1
mocp -M $wf/.moc2 -l $wf/w/stop.mp3 >/dev/null 2>&1
sleep 3
amixer set 'Master' ${volmin}% >/dev/null 2>&1

[ -f $wf/mp3_found ] && mocp -M $wf/.moc1 -U && fadein
na ir pats counter.py
#!/usr/bin/python
#import Tkinter as tk
from Tkinter import *
from time import sleep
import os
def togglepauseplay(e=None): os.popen('mocp -M /root/c/.moc1 -G')
def mforward(e=None): os.popen('mocp -M /root/c/.moc1 -k 10')
def mrewind(e=None): os.popen('mocp -M /root/c/.moc1 -k -10')
def mstop(e=None): os.popen('mocp -M /root/c/.moc1 -s')
def mplay(e=None): os.popen('mocp -M /root/c/.moc1 -p')
def mnext(e=None): os.popen('mocp -M /root/c/.moc1 -f')
def mprev(e=None): os.popen('mocp -M /root/c/.moc1 -r')
def decrease():
  global job, curtim
  tim.configure(text=curtim)
  if curtim>=0:
    curtim=curtim-1
    job=root.after(1000, decrease)
  else:
    stop()
def start(e=None):
  global job, var, curtim, timval, curind, indval, curser, serval
  if var==5 and job==0:
      curtim=timval
      os.popen('/root/c/start')
      decrease()
def stop(e=None):
  global job, timval, curind, curser, serval, indval
  if job!=0:
    root.after_cancel(job)
    job=0
    os.popen('/root/c/stop &')
    sleep(5)
    if (curind==indval and curser==serval):
      power()
      return 0
    nextind()
    tim.configure(text=timval)
def power(e=None):
  global modval, indval, serval, timval, var, job
  if job==0:
    job=0
    var=0
    modval=""
    indval=0
    serval=0
    timval=0
    mod.configure(text="Mode", fg="gray15")
    ind.configure(text="Index", fg="gray15")
    ser.configure(text="Series", fg="gray15")
    tim.configure(text="Sec", fg="gray15")
def n(i):
  global var, modval, indval, serval, timval
  if var==1:
    modval=("Train","Comp")[i==0]
    mod.configure(text=modval)
  if var==3:
    indval=i
    if indval==0: indval=1
    ind.configure(text=indval)
  if var==2:
    serval=serval*10+i
    if serval==0: serval=1
    if serval>=25: serval=25
    ser.configure(text=serval)
  if var==4:
    timval=timval*10+i
    if timval==0: timval=1
    if timval>=300: timval=300
    tim.configure(text=timval)


def ok(e=None):
  global var, modval, indval, serval, timval, curind, curser
  if var<5: font="">
    var=var+1
    if var==1:
      mod.configure(fg="yellow")
    if var==2:
      if modval=="Train" or modval=="Comp": mod.configure(fg="gray50")
      else: mod.configure(fg="gray15")
      ser.configure(fg="yellow")
    if var==3:
      if serval>0 and serval<26: fg="gray50" font="" ser.configure="">
      else: ser.configure(fg="gray15")
      ind.configure(fg="yellow")
    if var==4:
      if indval>0 and indval<10: fg="gray50" font="" ind.configure="">
      else: ind.configure(fg="gray15")
      tim.configure(fg="yellow")
    if var==5:
      if modval=="": modval="Train"
      if indval==0: indval=1
      if serval==0: serval=12
      if timval==0: timval=120
      if modval=="Train": os.popen('touch /root/c/mp3_play')
      else: os.popen('rm -rf /root/c/mp3_play')
      curind=1
      curser=1
      curtime=timval
      updinfo()
def reset(e=None):
  global var, modval, indval, serval, timval
  if var==1: modval=""; mod.configure(text="Mode")
  if var==3: indval=0; ind.configure(text="Index")
  if var==2: serval=0; ser.configure(text="Series")
  if var==4: timval=0; tim.configure(text="Sec")
def prevind(e=None):
  global job, curind, indval, curser
  if job==0:
    if curind>1:
      curind=curind-1
    else:
      if curser>1:
        curser=curser-1
        curind=indval
    updinfo()
def nextind(e=None):
  global job, curind, indval, curser, serval
  if job==0:
    if curind
      curind=curind+1
    else:
      if curser
        curser=curser+1
        curind=1
    updinfo()
def updinfo(e=None):
  global curind, indval, curser, serval, modval, timval
  ind.configure(fg="yellow", text="I:"+str(curind)+"/"+str(indval))
  ser.configure(fg="green", text="S:"+str(curser)+"/"+str(serval))
  mod.configure(fg="gray15", text=modval)
  tim.configure(fg="white", text=timval)
var=10
val=0
modval=""
indval=0
serval=0
timval=0
job=0
k="b"
root=Tk()
w=root.winfo_screenwidth()/2
h=root.winfo_screenheight()/2
if k=="wb":
  root.bind('o', prevind)
  root.bind('p', nextind)
  root.bind('', power)
  root.bind('e', ok)
  root.bind('q', reset)
  root.bind('u', start)
  root.bind('y', stop)
  root.bind('w', lambda e: n(0))
  root.bind('3', lambda e: n(1))
  root.bind('7', lambda e: n(2))
  root.bind('1', lambda e: n(3))
  root.bind('', lambda e: n(4))
  root.bind('4', lambda e: n(5))
  root.bind('5', lambda e: n(6))
  root.bind('-', lambda e: n(7))
  root.bind('=', lambda e: n(8))
  root.bind('9', lambda e: n(9))
  root.bind('t', togglepauseplay)
  #root.bind(']', mplay)
  #root.bind('[', mstop)
  ##root.bind('o', mrewind)
  ##root.bind('p', mforward)
  #root.bind('a', gtournament)
  #root.bind('s', gtraining)
  #root.bind('p', mnext)
  #root.bind('o', mprev)
else:
  #w=640; h=480
  root.bind('o', prevind)
  root.bind('p', nextind)
  root.bind('', power)
  root.bind('', ok)
  root.bind('', reset)
  root.bind('', start)
  root.bind('', stop)
  root.bind('0', lambda e: n(0))
  root.bind('1', lambda e: n(1))
  root.bind('2', lambda e: n(2))
  root.bind('3', lambda e: n(3))
  root.bind('4', lambda e: n(4))
  root.bind('5', lambda e: n(5))
  root.bind('6', lambda e: n(6))
  root.bind('7', lambda e: n(7))
  root.bind('8', lambda e: n(8))
  root.bind('9', lambda e: n(9))
if (1.0*w/h)<1 .5:="" ftim="h/6*5</font">
else: ftim=h/8*7
ytim=(h/2)-(ftim/2)
finfo=h/7
root.wm_title("Counter 4 STRELE.LT")
root.configure(bg='black')
root.geometry('%dx%d+%d+%d' % (w, h, 0, 0))
tim=Label(root, text="Sec", fg="gray5", bg="black", font=('Times', -ftim, 'bold'))
mod=Label(root, text="Mode", fg="gray5", bg="black", font=('Times', -finfo))
ind=Label(root, text="Index", fg="gray5", bg="black", font=('Times', -finfo))
ser=Label(root, text="Series", fg="gray5", bg="black", font=('Times', -finfo))
tim.place(x=0, y=ytim)
mod.place(x=0, y=0)
ser.place(x=w/3, y=0)
ind.place(x=w/3*2, y=0)


root.mainloop()

Na o čia keletas screenshoot`ų. Tik ką pasikrovus vaizdelis būna toks. Jei yra įkištas USB ir ten buvo rasta *.mp3 failų jie pradeda groti randomu.



Dabar spaudžiam POWER knopkiuką. Ji skirta taip pat jei norim pakeist nustatymus. Ją paspaudus viskas nuresetinama ir reik nustatyt iš naujo:



Taigi pasirenkam režimą varžybos ar treniruotė. 0 - varžybos, betkuris kitas skaičius - treniruotė. Spaudžiam ENTER (tarp 0 ir Vol- mygtukų) kad pereitume prie kito parametro.



Taip nustatos serijų skaičių. Min-1 max-25. Indeksų skaičių: min-1, max-9. Ir laiką: min-1 (dabar pagalvojau gal ir nelogiška), max-300. Dar kartą ENTER:



ir dabar galime spausti Play kad pradėt laiko skaičiavimą. Beje jei suklydom vesdami skaičius galime arba spausti reset laukeliui (rodyklė į kairę nuo 0), arba tiesiog POWER. Jei atsirado poreikis prsukti kitą indexa į priekį ar atgal yra pora mygtukų UP (po Rec) ir Down (po Stop). Pats Rec mygtukas padaro dainai pauze arba paleidžia toliau. Žinome čia dar prikamšiau visokių apsaugų nuo neteisingų reikšmių ir pan. Manu Right ir Left mygtukus poto panaudosiu pakeisti dainai. Taip pat vol+ ir vol- atitinkamai, kad nereiktų bėgti prie kolonėlių.
   Tai vat toks tad kūrinys. Planuoju dar jį patį panaudot kaip web serverį į kurį perkelsiu kažkada anksčiau rašytą varžybų rezultatų saugojimo programą. Bus galima prieit ir suvedinėt rezultatus per kokį liešiamą telefoną, o rezultatus atvaizduot ekrane prijungtame prie Banano :)
   Beliko sulaukti kabelio, kuris vis dar keliauja iš Kinojos ir surasti kokį nereikalingą 5v maitinimo šaltinį.