การเขียนโปรแกรมต่อ GPS ด้วยคอมโพเน็นต์ OpenGPSX (ภาค 4)

OpenGPSX component on SourceForge

  • ผมได้นำ component ตัวนี้ไปใส่ใน SourceForge.net เป็นที่เรียบร้อยแล้ว ถ้าต้องการตัวที่ update ก็ไปดาวน์โหลดกันได้เลยครับ หน้าตาของ OpenGPSX บน sourceforge ก็ประมาณดังรูปด้านล่าง

OpenGPSX component บน SourceForge.net

  • จากตอนที่แล้วเราทำการแปะคอมโพเน็นต์ลงบนฟอร์ม เพื่อทดสอบอย่างง่าย ต่อไปจะเปิด project ของ Lazarus ที่ผมเขียนขึ้นเพื่อนำคอมโพเน็นต์มาใช้งาน สามารถดาวน์โหลดตามลิงค์นี้ opengpsproject.zip ก่อนจะเปิด project นี้ต้องติดตั้งตัวคอมโพเน็นต์ ที่ผมกล่าวไปแล้วในภาคที่ 3 ก่อนนะครับ ไม่งั้นจะ Error เมื่อดาวน์โหลดมาแล้วก็ unzip ไปไว้ตรงไหนก็ได้

เปิดโปรแกรมทดสอบ

  • รัน Lazarus คลิกที่เมนู Project > Open Project…

เปิดไฟล์ opengpstest.lpi

  • เมื่อเปิดไฟล์ opengpstest.lpi แล้ว ที่ source editor ของ Lazarus คลิกไปที่ main กด F12 บนคีย์บอร์ดดูเพื่อดูฟอร์ม

OpenGPSX Test Project

ตั้ง property ให้ object

  • เมื่อเราแปะ object ลงบนฟอร์ม Lazarus จะตั้งชื่อให้ NMEADecode1, GPSSkyplot1, GPSTarget1, GPSPortConnected1 และ GPSSignalplot1 เพื่อให้ object แต่ละตัวรู้จักกันจะต้องเพิ่มโค้ดประมาณ 3 บรรทัดที่ FormCreate ดังที่ผมคอมเม็นต์ไว้ครับ
      [sourcecode language=”delphi”]

 

      procedure TForm1.FormCreate(Sender: TObject);

 

      begin

 

      FNMEAs := TStringList.Create;

 

      InitControls;

 

      FStop := false;

 

      cmdStopPlay.Enabled := false;

 

      {Don’t forget to assign for the following objects.}

 

      GPSTarget1.NMEADecode := NMEADecode1;

 

      GPSSkyplot1.NMEADecode := NMEADecode1;

 

      GPSSignalPlot1.NMEADecode := NMEADecode1;

 

      FSuccess := false;

 

      end;

 

    [/sourcecode]

หลักการทำงานของ object

  • ถ้าต่อกับเครื่อง GPS ตัว GPSPortConnected1 จะทำการเชื่อมกับ serial port เมื่อตั้งค่าต่างๆแล้วผ่านทางเมธอด GPSPortConnected1.SetupPort ทำการ connect เข้ากับ GPS ด้วยเมธอด GPSPortConnected1.OpenPort เครื่อง GPS จะส่งประโยค NMEA ผ่านทาง serial port ด้วยการสร้างอีเวนต์  GPSPortConnected1RxData ผู้ใช้ก็มาดักจับประโยค NMEA ที่นี่ โดยการเอา NMEADecode1 มาจับเอาประโยค NMEA ผ่านทาง property “Sentence”
      [sourcecode language=”delphi”]

 

      procedure TForm1.GPSPortConnected1RxData(Sender: TObject; Instring : string);

 

      begin

 

      //There are many empty string lines which come from TSdpoSerial.

 

      //Check it out.

 

      if InString <> ” then

 

      begin

 

      NMEADecode1.Sentence := Instring;

 

      if (NMEADecode1.Success) then

 

      memo1.Lines.Add(Instring);

 

      end;

 

      end;

 

    [/sourcecode]
  • NMEADecode1 เมื่อทำการแปลสตริง NMEA ที่รู้จักแล้วถ้าสำเร็จจะส่งข้อมูลผ่านทางอีเวนต์ OnNMEA (รวมประโยค NMEA ที่แปลแล้วทุกๆประโยค) และกระจายอีเวนต์แยกไปตามรูปประโยค NMEA เช่น OnGGA, OnRMC, OnGSV, OnGLL เป็นต้น และ object ตัวนี้จะสร้างอีเวนต์พิเศษคือ OnGPSTarget, OnGPSSkyplot และ OnGPSSignalplot เพื่อส่งข้อมูลที่แปลแล้วไปให้ class TGPSTarget, TGPSSkyplot และ TGPSSignalplot ตามลำดับ
  • GPSTarget1, GPSSkyplot1 และ GPSSignalplot1 เมื่อได้รับข้อมูล NMEADecode1 ก็จะทำหน้าที่ของตัวเอง

ทดสอบโดยการเล่นไฟล์ NMEA

  • ในการทดสอบโปรแกรม บางท่านอาจจะไม่มีเครื่อง GPS ให้ลอง ผมได้เตรียมไฟล์ NMEA ให้โดยอยู่ที่โฟลเดอร์ “Data” เมื่อรัน opengpstest.lpi แล้ว ที่ด้านล่างจะมี Button ให้อยู่ 3 ตัว คลิกที่ัตัว “Open NMEA File…” ผมจะลองเปิดไฟล์ gpslog-mod.txt เสร็จแล้วก็คลิกที่ปุ่ม “Play NMEA >>” จะหยุดเล่นเวลาไหนก็คลิกที่ปุ่ม “Stop” ได้ครับ
ทดสอบด้วยการเล่นไฟล์ NMEA
  • สำหรับ TGPSTarget มี property ที่สามารถตั้งค่าให้เลือกตั้งค่าพิกัดจุดหมายปลายทางได้เองหรือจะให้เลือกเอาจากประโยค $GPWPL ก็ได้ สังเกตว่าไฟล์นี้ขาดประโยค $GPVTG มาลองดูโค้ดที่ implement NMEA ที่ decode มาแล้ว
      [sourcecode language=”delphi”]

 

      {TNMEADecode is full of all decoded NMEA sentences.}

 

      procedure TForm1.NMEADecode1NMEA(Sender: TObject; NMEA: TNMEADecode);

 

      var

 

      dLat, dLong : double;

 

      begin

 

      case NMEA.MessageType of

 

      GGAMsg :

 

      begin

 

      with NMEA.GGA do

 

      begin

 

      lblGGAGeoidal.Caption := Separation + ‘ ‘ + SeparationUnits;

 

      lblGGAAltitude.Caption := Altitude + ‘ ‘ + AltitudeUnits;

 

      lblGGASatCount.Caption := SatsInUse;

 

      dLat := abs(strtofloat(LatitudeDegree));

 

      dLong := abs(strtofloat(LongitudeDegree));

 

      lblGGALat.Caption := format(‘%9.6f’, [dLat]) + ‘ (‘ + LatHemis + ‘)’;

 

      lblGGALong.Caption := format(‘%9.6f’, [dLong]) + ‘ (‘ + LongHemis + ‘)’;

 

      lblGGAHDOP.Caption := HDOP;

 

      lblGGAUTCTime.Caption := UTC;

 

      if (FixQuality = ‘0’) then

 

      lblGGAQuality.Caption := ‘Invalid’

 

      else if (FixQuality = ‘1’) then

 

      lblGGAQuality.Caption := ‘GPS Fix’

 

      else if (FixQuality = ‘2’) then

 

      lblGGAQuality.Caption := ‘DGPS Fix’;

 

      end;

 

      end;

 

      GSAMsg :

 

      begin

 

      with NMEA.GSA do

 

      begin

 

      if (FixStatus = ‘1’) then

 

      lblGSAFix.Caption := ‘Fix not available’

 

      else if (FixStatus = ‘2’) then

 

      lblGSAFix.Caption := FixStatus + ‘D’

 

      else if (FixStatus = ‘3’) then

 

      lblGSAFix.Caption := FixStatus + ‘D’;

 

      if (Mode = ‘A’) then

 

      lblGSAMode.Caption := ‘Automatic 2D/3D’

 

      else if (Mode = ‘M’) then

 

      lblGSAMode.Caption := ‘Manual’;

 

      lblGSAHDOP.Caption := HDOP;

 

      lblGSAVDOP.Caption := VDOP;

 

      lblGSAPDOP.Caption := PDOP;

 

      end;

 

      end;

 

      RMCMsg :

 

      begin

 

      with NMEA.RMC do

 

      begin

 

      if (Status = ‘A’) then

 

      lblRMCValidity.Caption := ‘Active’

 

      else if (Status = ‘V’) then

 

      lblRMCValidity.Caption := ‘Invalid’;

 

      dLat := abs(strtofloat(LatitudeDegree));

 

      dLong := abs(strtofloat(LongitudeDegree));

 

      lblRMCLat.Caption := format(‘%9.6f’, [dLat]) + ‘ (‘ + LatHemis + ‘)’;

 

      lblRMCLong.Caption := format(‘%9.6f’, [dLong]) + ‘ (‘ + LongHemis + ‘)’;

 

      lblRMCSpeed.Caption := format(‘%5.1f’, [strtofloat(Speed) * 1.852]) + ‘ Km/h’;

 

      lblRMCDate.Caption := UTCDate;

 

      lblRMCTime.Caption := UTCTime;

 

      lblRMCTrue.Caption := TrueCourse;

 

      if (MagneticVariation = ‘-9999’) then

 

      lblRMCMagVar.Caption := ”

 

      else

 

      lblRMCMagVar.Caption := MagneticVariation + ‘ ‘ + MagDeviation;

 

      end

 

      end;

 

      WPLMsg :

 

      begin

 

      with NMEA.WPL do

 

      begin

 

      lblWPName.Caption := WayPointName;

 

      lblWPLatitude.Caption := Latitude;

 

      lblWPLongitude.Caption := Longitude;

 

      end;

 

      end;

 

      GLLMsg :

 

      begin

 

      with NMEA.GLL do

 

      begin

 

      dLat := abs(strtofloat(LatitudeDegree));

 

      dLong := abs(strtofloat(LongitudeDegree));

 

      lblGLLLat.Caption := format(‘%9.6f’, [dLat]) + ‘ (‘ + LatHemis + ‘)’;

 

      lblGLLLong.Caption := format(‘%9.6f’, [dLong]) + ‘ (‘ + LongHemis + ‘)’;

 

      lblGLLTime.Caption := UTCTime;

 

      if (Status = ‘A’) then

 

      lblGLLStatus.Caption := ‘Valid’

 

      else if (Status = ‘V’) then

 

      lblGLLStatus.Caption := ‘Invalid’;

 

      end;

 

      end;

 

      PGRMMsg:

 

      begin

 

      with NMEA.PGRMM do

 

      lblGarminMapDatum.Caption := MapDatum;

 

      end;

 

      PGRMZMsg:

 

      begin

 

      with NMEA.PGRMZ do

 

      begin

 

      if (UnitAltitude = ‘f’) then

 

      lblGarminAltitude.Caption := Altitude + ‘ ‘ + ‘Feet’

 

      else

 

      lblGarminAltitude.Caption := Altitude + ‘ ‘ + UnitAltitude;

 

      lblGarminPosFix.Caption := PositionFix;

 

      end;

 

      end;

 

      PGRMEMsg:

 

      begin

 

      with NMEA.PGRME do

 

      begin

 

      lblGarminHPE.Caption := HPE + ‘ ‘ + UnitHPE;

 

      lblGarminVPE.Caption := VPE + ‘ ‘ + UnitVPE;

 

      lblGarminSEPE.Caption := SEPE + ‘ ‘ + UnitSEPE;

 

      end;

 

      end;

 

      end;

 

      end;

[/sourcecode]

  • สังเกตว่าพารามิเตอร์ NMEA : TNMEADecode จะแยกชนิดของประโยคด้วย property “MessageType”

ทดสอบเล่นไฟล์ NMEA อีกไฟล์

  • ลองเปิดไฟล์ NMEA อีกตัวคือไฟล์ “griffith-park.nmea” ซึ่งผมดาวน์โหลดได้จาก internet ดูค่าพิกัดแล้วน่าจะอยู่แถวๆ รัสเซีย ลองทดสอบดูกัน
ทดสอบอีกไฟล์
  • สังเกตว่าไฟล์ทดสอบนี้ำจะไม่มีประโยค $GPGLL และ $GPWPL แต่จะมีประโยค $GPVTG มาแทน เอาละครับมาต่อตอนต่อไป ผมอาจจะลองทดสอบดูใน Ubutu Linux หรืออาจจะทดสอบต่อกับเครื่อง GPS ผ่าน serial port

Leave a Reply

Your email address will not be published. Required fields are marked *