[Linux] Beagleboard GPS SMS Cellphone Module ready!

Prototype without flaws, works 100% This prototype worked out of the box. I had the PCB’s in, soldered them, plugged it in the computer, hey presto: worked.

Module design, schematics, internals, etc

I designed this module myself. You can see everything about how it i had it produced here: LINK.

Rembrandt is pleased

As i had some empty space, i decided to let an etch of rembrandt be etched on the bottom of the PCB. Worked out great.
[caption id="attachment_1271" align="aligncenter" width="300" caption="Bottom of the module"][/caption]

Short Introduction Video

http://www.youtube.com/watch?v=uVCx1S8RLfs

Pictures!

[caption id="attachment_1272" align="aligncenter" width="300" caption="Module with the GPRS and GPS antenna's on the left, USB on the right."][/caption] [caption id="attachment_1273" align="aligncenter" width="300" caption="Close-up"][/caption]

This modules takes python scripts

This module can operate autonomously if you give it a python script. Here below is a script, that, when loaded to the module, sends anyone who textmessages “position” to the module, the GPS position back. Also, there is a built in function that resets the module when it fails when it reaches a GPS altitude of 24km. There are two files: run.py and main.py. Download RSTERM.exe on windows. Make sure you set the baudrate to 115200 In the Python menu, choose your folder with these scripts. Press compile, then upload the two .pyo files. Then, set run.py as the active script, then select the boot after 10 seconds mode, then reboot and voila you’re done, the script will automatically load. If you now send an sms to the module, i get an sms back with the GPS position! WATCH OUT: When i was editing the code, it would NOT work if i included too many spaces or tabs (=indentations). So try to avoid those and just write your code on one level.

run.py

  1. import main

main.py

  1. # Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
  2. # THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS
  3. # PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR
  4. # OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS
  5. # LICENSE OR COPYRIGHT LAW IS PROHIBITED.
  6. # Original code Alexei Karpenko
  7. # Modified by Tim Zaman
  8. ##### Config #####
  9. sms_password = 'pwd'
  10. remote_phone_number = '+31612345678'
  11. ##### Constants #####
  12. TRUE = 1
  13. FALSE = 0
  14. line_cut = FALSE
  15. had_fix = FALSE
  16. nofix_count = 0
  17. ##### Modules #####
  18. #Use serial
  19. import SER
  20. #Use build in module
  21. import MOD
  22. #Use AT command interface
  23. import MDM
  24. #Use GPIO functions
  25. import GPIO
  26. ###### General Functions ######
  27. def cutoff():
  28.     GPIO.setIOvalue(8, 1)
  29.     #sms_send(remote_phone_number,'Cut line!')
  30. def cutoff_cancel():
  31.     GPIO.setIOvalue(8, 0)
  32. def getActualPosition():
  33.     MDM.send('AT$GPSACPr', 0)
  34.     pos = MDM.receive(1)
  35.     pos = pos.split('rn')
  36.     return pos[1]
  37. def reset_system():
  38.     MDM.send('AT#SHDNr', 0)
  39.     temp = MDM.receive(1)
  40. def reset_gps():
  41.     MDM.send('AT$GPSR=1r', 0)
  42.     temp = MDM.receive(1)
  43. def reset_gps2():
  44.     MDM.send('AT$GPSR=0r', 0)
  45.     temp = MDM.receive(1)
  46. #Debug message
  47. def debugmsg(msgtext):
  48.     msgtext = msgtext.replace('r', 'r')
  49.     msgtext = msgtext.replace('n', 'n')
  50.     print msgtext
  51.     SER.send(msgtext + 'rn')
  52.     #f = open('log.txt','ab')
  53.     #f.write(msgtext + 'n')
  54.     #f.close()
  55. #GPS status
  56. def gps_status(gpspos):
  57.     global had_fix
  58.     debugmsg('Retrieving GPS status')
  59.     gpspos_parts = gpspos.split(',')
  60.     if ( (gpspos_parts[5] == '2') or (gpspos_parts[5] == '3') ): #2D or 3D fix
  61.         debugmsg('GPS fix "' + gpspos_parts[5] + '" ie valid');
  62.         status = TRUE
  63.         # GPS crash prevention:
  64.         if (gpspos_parts[10] == '00'):
  65.             if (had_fix == TRUE):
  66.                 reset_gps()
  67.                 had_fix = FALSE
  68.         else:
  69.             had_fix = TRUE
  70.     else:
  71.         debugmsg('GPS fix "' + gpspos_parts[5] + '" ie not valid');
  72.         status = FALSE
  73.         # GPS crash prevention:
  74.         if (had_fix == TRUE):
  75.             reset_gps()
  76.             had_fix = FALSE
  77.     return status
  78. ###### SMS Process Functions ######
  79. #Process SMS messages
  80. def sms_proceses(gpspos):
  81.     debugmsg('Process SMS')
  82.     #List SMS
  83.     smsmsgs = sms_list()
  84.     totalsms = len(smsmsgs)
  85.     #debugmsg('SMS total: %d' % totalsms)
  86.     #Go throguh SMS messages
  87.     for smsmsgindex in range(0, totalsms):
  88.         debugmsg('Message: %d' % smsmsgindex)
  89.         #Delete SMS (it is being processed now)
  90.         status = sms_delete(smsmsgs[smsmsgindex]['id'])
  91.         #If status deleted ok
  92.         if (status == TRUE):
  93.             #debugmsg('List SMS id: %d, from: %s, msg: %s' % (smsmsgs[smsmsgindex]['id'], smsmsgs[smsmsgindex]['from'], smsmsgs[smsmsgindex]['msg']))
  94.             #Split SMS message into parts
  95.             smsmsgparts = smsmsgs[smsmsgindex]['msg'].split(' ')
  96.             #If at least 2 parts
  97.             if (len(smsmsgparts) > 1):
  98.                 #Check if password valid
  99.                 if (smsmsgparts[0].lower() == sms_password):
  100.                     debugmsg('Password valid')
  101.                     #If position requested
  102.                     if (smsmsgparts[1].lower() == 'pos') or (smsmsgparts[1].lower() == 'position'):
  103.                         debugmsg('Action: Position requested')
  104.                         #If GPS position fix valid
  105.                         if (gps_status(gpspos) == TRUE):
  106.                             #gpsdataparts = gpspos.split(',')
  107.                             #senddata = 'Lat: ' + gpsdataparts[1] + ', Lon: ' + gpsdataparts[2] + ', Heading: ' + gpsdataparts[6] + ', Speed: ' + gpsdataparts[7] + ' km/hr'
  108.                             senddata = gpspos;
  109.                         else:
  110.                             senddata = 'No GPS Fix'
  111.                         #Send SMS
  112.                         sms_send(smsmsgs[smsmsgindex]['from'], senddata)
  113.                     elif (smsmsgparts[1].lower() == 'cut'):
  114.                         cutoff()
  115.                     elif (smsmsgparts[1].lower() == 'oops'):
  116.                         cutoff_cancel()
  117.                     elif (smsmsgparts[1].lower() == 'rgps'):
  118.                         reset_gps()
  119.                     elif (smsmsgparts[1].lower() == 'rgps2'):
  120.                         reset_gps2()
  121.                     elif (smsmsgparts[1].lower() == 'rsys'):
  122.                         reset_system()
  123.                     else:
  124.                         debugmsg('Action: Unknown')
  125.                 else:
  126.                     debugmsg('Password invalid')
  127.         else:
  128.             debugmsg('Unable to delete')
  129. ###### SMS Library Functions ######
  130. #Setup SMS
  131. def sms_setup():
  132.     debugmsg('Setting up SMS')
  133.     MDM.send('AT+CMGF=1r', 0)
  134.     res = MDM.receive(50)#5 sec
  135.     MOD.sleep(1)#wait 0.1sec
  136.     debugmsg('SMS setup: ' + res)
  137. #List SMS
  138. def sms_list():
  139.     #Note: Command will not return anything if SIM is not ready
  140.     debugmsg('List SMS')
  141.     #MDM.send('AT+CMGL="REC UNREAD"r', 0) #ALL REC UNREAD   STO SENT
  142.     MDM.send('AT+CMGL="REC UNREAD"r', 0)
  143.     #smslist = ''
  144.     #res = MDM.receive(50)#5 sec
  145.     #smslist = smslist + res
  146.     #while (res.find('rnOKrn') == -1):
  147.     #    res = MDM.receive(10)
  148.     #    smslist = smslist + res
  149.     smslist = ''
  150.     res = ''
  151.     timeout = MOD.secCounter() + 60
  152.     while ( (res.find('rnOKrn') == -1) and (MOD.secCounter() < timeout) ):
  153.         debugmsg('Timeout now: %d timeout: %d' % (MOD.secCounter(), timeout))
  154.         res = MDM.receive(50)
  155.         smslist = smslist + res
  156.         #debugmsg('get %s' % smslist)
  157.     MOD.sleep(1)#wait 0.1sec
  158.     smsparts = smslist.split('rn')
  159.     smspartslen = len(smsparts)
  160.     #debugmsg('SMS Parts %d' % smspartslen)
  161.     smsmsgs = []
  162.     if (smspartslen-2 > 0) and (smsparts[smspartslen-2] == 'OK'):
  163.         #If there is at least 1 message
  164.         if (smspartslen >= 6):
  165.             #Go through all messages
  166.             for partno in range(1, smspartslen):
  167.                 #Find out if this is an cmgl line
  168.                 cmglparts = smsparts[partno].split('CMGL: ')
  169.                 #If at least 2 parts, leading cmgl and data
  170.                 if (len(cmglparts) > 1) and (cmglparts[0] == '+') and (partno+1 <= smspartslen):
  171.                     #debugmsg('Found CMGL %d: %s' % (partno, smsparts[partno]))
  172.                     #debugmsg('Text %d: %s' % (partno+1, smsparts[partno+1]))
  173.                     #Split msg info line into parts
  174.                     msginfoparts = cmglparts[1].split(',')
  175.                     #Check have all parts
  176.                     #if (len(msginfoparts) > 5):
  177.                     if (len(msginfoparts) > 4):
  178.                         #int() may fail
  179.                         try:
  180.                             #Convert id to integer
  181.                             msginfoparts[0] = int(msginfoparts[0])
  182.                             #Remove quotes
  183.                             msginfoparts[2] = msginfoparts[2].replace('"', '')
  184.                             #msginfoparts[4] = msginfoparts[4].replace('"', '')
  185.                             #msginfoparts[5] = msginfoparts[5].replace('"', '')
  186.                             smsmsgs.append({'id': msginfoparts[0], 'from': msginfoparts[2], 'msg': smsparts[partno+1]})
  187.                             debugmsg('SMS id: %d, from: %s, msg: %s' % (msginfoparts[0], msginfoparts[2], smsparts[partno+1]))
  188.                         except Exception:
  189.                             debugmsg('Error CMGL %d: %s' % (partno, smsparts[partno]))
  190.         debugmsg('SMS total: %d' % len(smsmsgs))
  191.     else:
  192.         debugmsg('No SMS messages available')
  193.     return smsmsgs
  194. #SMS Delete
  195. def sms_delete(delindex):
  196.     debugmsg('SMS Delete: %d' % delindex)
  197.     MDM.send('AT+CMGD=' + str(delindex) + 'r', 0)
  198.     res = MDM.receive(50)#5 sec
  199.     MOD.sleep(1)#wait 0.1sec
  200.     if (res == 'rnOKrn'):
  201.         status = TRUE
  202.     else:
  203.         status = FALSE
  204.     return status
  205. #SMS Send
  206. def sms_send(to, text):
  207.     debugmsg('Send SMS to: %s, MSG: %s' % (to, text))
  208.     MDM.send('AT+CMGS="' + to + '"r', 0)
  209.     res = MDM.receive(50)#5 sec
  210.     MOD.sleep(1)#wait 0.1sec
  211.     #Check for SMS prompt
  212.     if (res == 'rn> '):
  213.         #Send SMS message text
  214.         MDM.send(text, 0)
  215.         #End SMS
  216.         MDM.sendbyte(0x1A, 0)
  217.         res2 = MDM.receive(180)#5 sec
  218.         MOD.sleep(1)#wait 0.1sec
  219.         if (res2.find('rnOKrn') != -1):
  220.             debugmsg('SMS sent')
  221.             status = TRUE
  222.         else:
  223.             debugmsg('SMS Send: ' + res2)
  224.             debugmsg('Did not get SMS sent confirmation')
  225.             status = FALSE
  226.             MDM.receive(1); # may prevent +CMS ERROR: 331 crash
  227.     else:
  228.         debugmsg('SMS Send: ' + res)
  229.         debugmsg('Did not receive SMS prompt')
  230.         #Abort SMS (just in case)
  231.         MDM.sendbyte(0x1B, 0)
  232.         MOD.sleep(1)#wait 0.1sec
  233.         status = FALSE
  234.     return status
  235. ##################################################################################
  236. def constraints(gpspos):
  237.     global line_cut
  238.     gpspos_parts = gpspos.split(',')
  239.     if ( (gpspos_parts[5] == '2') or (gpspos_parts[5] == '3') ): #2D or 3D fix
  240.         lat_temp = gpspos_parts[1].split('.')
  241.         lon_temp = gpspos_parts[2].split('.')
  242.         lat = int(lat_temp[0])
  243.         lon = int(lon_temp[0])
  244.         debugmsg('lat = ' + repr(lat) + ' lon = ' + repr(lon))
  245.         if ( (4320 < lat) and (8036 < lon) ):
  246.             debugmsg('Within constraints.')
  247.         elif ( line_cut == FALSE ):
  248.             debugmsg('Outside of constraints, cutting line!')
  249.             cutoff()
  250.             line_cut = TRUE
  251.         else:
  252.             debugmsg('Outside of constraints.')
  253. ###### Init ######
  254. # configure GPIO pins
  255. GPIO.setIOdir(8,0,1) # GPIO8 0 output
  256. SER.set_speed('115200','8N1')
  257. SER.send('rn--------------------rnrn')
  258. debugmsg('Running...');
  259. #Set verbose error reporting
  260. MDM.send('AT+CMEE=2r', 0)
  261. MDM.receive(50)#5 sec
  262. MOD.sleep(1)#wait 0.1sec
  263. #May be required in North America / Canada to switch the unit to 900/1900MHz frequency (uncomment if in those areas)
  264. #MDM.send('AT#BND=3r', 0)
  265. #MDM.receive(1)#0.1sec
  266. #MOD.sleep(1)#wait 0.1sec
  267. gpspos_lastvalid = ''
  268. #Setup SMS
  269. sms_setup()
  270. #Main loop
  271. while 1:
  272.     debugmsg('Entering loop')
  273.     #Retrieve current position
  274.     gpspos = getActualPosition()
  275.     debugmsg('Position: %s' % gpspos)
  276.     constraints(gpspos)
  277.     # A few tests:
  278.     #constraints('002317.908,4326.9364N,08027.2974W,4.0,286.4,2,152.30,10.94,5.90,110907,03')
  279.     #constraints('002317.908,4326.9364N,08211.2974W,4.0,286.4,2,152.30,10.94,5.90,110907,03')
  280.     #Retrieve GPS fix status
  281.     gps_statusnow = gps_status(gpspos)
  282.     # GPS crash prevention (reset GPS after ~10 minutes if no fix)
  283.     if (had_fix == FALSE):
  284.         nofix_count = nofix_count + 1
  285.         if (nofix_count == 60):
  286.             reset_gps()
  287.             nofix_count = 0
  288.     else:
  289.         nofix_count = 0
  290.     #Save last valid position
  291.     #If position fix valid, or none recorded already, use last retrieved
  292.     if ( (gps_statusnow == TRUE) or (gpspos_lastvalid == '') ):
  293.         gpspos_lastvalid = gpspos
  294.     #Check for / process new SMS messages
  295.     sms_proceses(gpspos_lastvalid)
  296.     debugmsg('Powersave for 10 seconds')
  297.     #Powersave for 10 seconds
  298.     MOD.powerSaving(10)
]]>

You may also like...

7 Responses

  1. Hoi Tim,
    Ik heb hier een aantal GM862 modules liggen en een beagleboard is onderweg.
    Om het wiel niet opnieuw uit te vinden zou ik graag gebruik maken van de pcb die jij hebt ontwikkeld. Heb je hier nog pcb’s van? Of het ontwerp? Dat zou mij snel op weg helpen. Uiteraard deel ik mijn bevindingen met je en zal ik onthouden dat jij de ontwikkelaar van het board bent.
    Kunnen we hier een keer contact over hebben?
    Met vriendelijke groet,
    Tijs van Roon

    • Tim says:

      Hoi Thijs, we kunnen overal contact over hebben, maar het schematic bijvoorbeeld staat hier http://www.timzaman.nl/?p=1165&lang=en . Als je een PCBtje wilt hebben kun je een euro of 5 paypallen, heb er nog een aantal liggen.

      • Hoi Tim,
        bedankt voor je antwoord. Ik heb helemaal niet opgemerkt dat hier een antwoord stond. Had een mailtje van je blog verwacht. Stom! Excuus dus!
        Het schema komt me goed van pas. Ik ga het (in de loop van de tijd) met de BeagleBone proberen die ik hier heb liggen. Die is voor mij wat praktischer.
        Ik laat je mijn bevindingen weten. Bedankt voor je hulp!

  2. Can you provide the Eagle files for the PCB? Thanks!

  3. Reuben Coelho says:

    Hey Tim,
    I am wondering if you could provide the eagle files for this project.
    Or is it possible for me to order one of these boards of you.
    Regards
    Reuben Coelho

  4. Jay says:

    How much for the module?

  5. Pavol says:

    Hello Tim,
    how can i order your board?
    thank you in advance