GPS Plug-in Source Code Walkthrough

Part 1 - GPS Project Overview and Required Hardware - GPS and USB
Part 2 - Install Serial Communication Library into RICOH THETA

This is a machine translation of a Japanese article by KA-2. The original article is here.


I will put a set of files of plugins created this time here . I touched two files in HttpConnector.java, MainActivity.java, among the files in the THETA plug-in SDK based on it. I will explain the code which added and modified in each file in the following into the block separately.

HttpConnector.java

Processing to execute webAPI from the plugin is summarized. It is like a parts group. In addition to manipulating THETA from the outside, webAPI can also be executed from a plugin. Please refer here for the command specification .

We added a command execution part necessary for making this plugin. It is better to review the structure of the program more carefully , but this time we are adding a new process with Copy & Minor modification, and there are many duplicated codes.

Code for HttpConnector.java

/ **
 * Set GPS (GNSS) Info
 *
 * @ return Error message (null is returned if successful)
 * / 
Public  String  SetGpsInfo ( String  Lat ,  String  Lng ,  String  Height ,  String  DateTimeZone )  { 
    HttpURLConnection  PostConnection  =  CreateHttpConnection ( "POST" ,  "/ Osc / Commands / Execute" ); 
    JSONObject  Input  =  New  JSONObject (); 
    String  ResponseData ; 
    String  errorMessage  =  null ; 
    InputStream  is  =  null;

    Try  { 
        // Send HTTP POST 
        Input . Put ( "Name" ,  "Camera.SetOptions" ); 
        JSONObject  Parameters  =  New  JSONObject (); 
        JSONObject  Options  =  New  JSONObject (); 
        JSONObject  GpsInfo  =  New  JSONObject ();

        GpsInfo . Put ( "Lat" , Lat ); 
        GpsInfo . Put ( "Lng" , Lng ); 
        GpsInfo . Put ( "_Altitude" , Height ); 
        GpsInfo . Put ( "_DateTimeZone" , DateTimeZone ); 
        GpsInfo . Put ( "_Datum " , " WGS 84 " );

        Options . Put ( "GpsInfo" ,  GpsInfo ); 
        Parameters . Put ( "Options" ,  Options ); 
        Input . Put ( "Parameters" ,  Parameters );

        OutputStream  os  =  PostConnection . GetOutputStream (); 
        os . Write ( input The . ToString . () GetBytes ()); 
        PostConnection . The connect (); 
        os . Flush (); 
        os . Close The ();

        is  =  postConnection . getInputStream (); 
        responseData  =  InputStreamToString ( is );

        // parse JSON data 
        JSONObject  output  =  new  JSONObject ( responseData ); 
        String  status  =  output . getString ( "state" );

        an if  ( status . the equals ( "error" ))  { 
            JSONObject  errors The  =  output . GetJSONObject ( "error" ); 
            errorMessage  =  errors The . getString ( "message" ); 
        } 
    }  catch  ( IOException  e )  { 
        e . printStackTrace (); 
        errorMessage  =  e . toString (); 
        InputStream  es  =  postConnection .GetErrorStream (); 
        Try  { 
            If  ( Es  =!  Null )  { 
                String  ErrorData  =  InputStreamToString ( Es ); 
                JSONObject  Output  =  New  JSONObject ( ErrorData ); 
                JSONObject  Errors  =  Output . GetJSONObject ( "Error" ); 
                ErrorMessage  =  Errors . GetString ( " message " ); 
            } 
        }  catch  ( IOException e1 )  { 
            e1 . printStackTrace (); 
        }  catch  ( JSONException  e1 )  { 
            e1 . printStackTrace (); 
        }  a finally  { 
            an if  ( es  =!  null )  { 
                the try  { 
                    es . close The (); 
                }  catch  ( IOException  e1 )  { 
                    e1 . printStackTrace (); 
                } 
            } 
        } 
    }  catch  ( JSONException E )  { 
        E . PrintStackTrace (); 
        ErrorMessage  =  E . ToString (); 
    }  Finally  { 
        If  ( Is  =!  Null )  { 
            Try  { 
                Is . Close (); 
            }  Catch  ( IOException  E )  { 
                E . PrintStackTrace (); 
            } 
        } 
    }

    return  errorMessage ; 
}

Processing of JSONObject will be described afterward, and processing of Exception system will be omitted.

Code to execute settings related to interval shooting

/ **
     * Set Interval Parameters
     *
     * @ return Error message (null is returned if successful)
     * / 
    public  String  setIntervalParam ( int  capInterval ,  int  capNumber )  { 
        HttpURLConnection  postConnection  =  createHttpConnection ( "POST" ,  "/ osc / commands / execute" ); 
        JSONObject  input  =  new  JSONObject (); 
    String  responseData ; 
    String  errorMessage  =  null ; 
    InputStream  is  =  null ;

    try  { 
        // send HTTP POST 
        input . put ( "name" ,  "camera.setOptions" ); 
        JSONObject  parameters  =  new  JSONObject (); 
        JSONObject  options  =  new  JSONObject ();

        Options . Put ( "CaptureInterval" ,  String . valueOf ( CapInterval )); 
        Options . Put ( "CaptureNumber" ,  String . valueOf ( CapNumber )); 
        Parameters . Put ( "Options" ,  Options ); 
        Input . Put ( "Parameters" ,  parameters );

        OutputStream  os  =  PostConnection . GetOutputStream (); 
        os . Write ( input The . ToString . () GetBytes ()); 
        PostConnection . The connect (); 
        os . Flush (); 
        os . Close The ();

        is  =  postConnection . getInputStream (); 
        responseData  =  InputStreamToString ( is );

        // parse JSON data 
        JSONObject  output  =  new  JSONObject ( responseData ); 
        String  status  =  output . getString ( "state" );

        an if  ( status . the equals ( "error" ))  { 
            JSONObject  errors The  =  output . GetJSONObject ( "error" ); 
            errorMessage  =  errors The . getString ( "message" ); 
        } 
    }  catch  ( IOException  e )  { 
        : approximately 
    }

    return  errorMessage ; 
}

Code for executing interval shooting start

/ **
     * startCapture
     *
     * @ return Error message (null is returned if successful)
     * / 
    Public  String  StartCapture ( String  Mode )  { 
        HttpURLConnection  PostConnection  =  CreateHttpConnection ( "POST" ,  "/ Osc / Commands / Execute" ); 
        JSONObject  Input  =  New  JSONObject (); 
        String  ResponseData ; 
        String  ErrorMessage  =  Null ; 
        InputStream  Is  =  Null ;

        try  { 
            // send HTTP POST 
            input . put ( "name" ,  "camera.startCapture" ); 
            JSONObject  parameters  =  new  JSONObject ();

            parameters . put ( "_mode" ,  mode ); 
            input . put ( "parameters" ,  parameters );

            OutputStream  os  =  PostConnection . GetOutputStream (); 
            os . Write ( input The . ToString . () GetBytes ()); 
            PostConnection . The connect (); 
            os . Flush (); 
            os . Close The ();

            is  =  postConnection . getInputStream (); 
            responseData  =  InputStreamToString ( is );

            // parse JSON data 
            JSONObject  output  =  new  JSONObject ( responseData ); 
            String  status  =  output . getString ( "state" );

            an if  ( status . the equals ( "error" ))  { 
                JSONObject  errors The  =  output . GetJSONObject ( "error" ); 
                errorMessage  =  errors The . getString ( "message" ); 
            } 
        }  catch  ( IOException  e )  { 
            : approximately 
        }

        return  errorMessage ; 
    }

Code to execute interval stop shooting

/ **
     * stopCapture
     *
     * @ return Error message (null is returned if successful)
     * / 
    Public  String  StopCapture ()  { 
        HttpURLConnection  PostConnection  =  CreateHttpConnection ( "POST" ,  "/ Osc / Commands / Execute" ); 
        JSONObject  Input  =  New  JSONObject (); 
        String  ResponseData ; 
        String  ErrorMessage  =  Null ; 
        InputStream  Is  =  Null ;

        try  { 
            // send HTTP POST 
            input . put ( "name" ,  "camera.stopCapture" );

            OutputStream  os  =  PostConnection . GetOutputStream (); 
            os . Write ( input The . ToString . () GetBytes ()); 
            PostConnection . The connect (); 
            os . Flush (); 
            os . Close The ();

            is  =  postConnection . getInputStream (); 
            responseData  =  InputStreamToString ( is );

            // parse JSON data 
            JSONObject  output  =  new  JSONObject ( responseData ); 
            String  status  =  output . getString ( "state" );

            an if  ( status . the equals ( "error" ))  { 
                JSONObject  errors The  =  output . GetJSONObject ( "error" ); 
                errorMessage  =  errors The . getString ( "message" ); 
            } 
        }  catch  ( IOException  e )  { 
            : approximately 
        }

        return  errorMessage ; 
    }

Code for checking the state of interval shooting

 / **
     * Acquire device status
     *
     * @return _captureStatus String
     * / 
    public  String  getCaptureStatus ()  { 
        HttpURLConnection  postConnection  =  createHttpConnection ( "POST" ,  "/ osc / state" ); 
        String  responseData ; 
        String  capStat  =  "" ; 
        InputStream  is  =  null ;

        try  { 
            // send HTTP POST 
            postConnection . connect ();

            is  =  postConnection . getInputStream (); 
            responseData  =  InputStreamToString ( is );

            Parse JSON data // 
            JSONObject  output  =  new new  JSONObject ( responseData ); 
            MFingerPrint  =  output . GetString ( "fingerprint" ); 
            JSONObject  status  =  output . GetJSONObject ( "state" ); 
            CapStat  =  status . GetString ( "_CaptureStatus" ); 
        }  catch  ( IOException  e )  { 
            : Abbreviation (It differs somewhat from the processing described above. Please download the complete set of projects and confirm it.) 
        }

        return  capStat ;

MainActivity.java

The main body of processing is here.
MainActivity is like a screen in smartphone application.
Although it dispatches processing when receiving an event of member operation, it can not directly perform serial communication or perform HTTP communication.

In this time, we decided to divide threads for serial communication at plug-in startup (strictly onResume).
In the thread, polling reception from the GPS / GNSS receiver and data for updating the position information inside THETA are prepared, the data is edited and set up to the inside.
Moreover, although there is a feeling of a backing up a little, I also perform the start / stop processing etc. of the interval shooting buffered at the reception of member operation.
Only the task of executing takePicture already described in the base SDK is handled, but it is safer to combine the internal web API command sender into one thread / task.

Although it is from the program structure talk, as a bonus function, processing to save the raw data of the NMEA 0183 format received from the GPS / GNSS receiver is also described. This is because THETA V becomes “GPS / GNSS logger that functions without photography”. It was convenient for debugging.

Definition of variables

Variables necessary for processing moromoro are arranged near the beginning of MainActivity.

// serial communication related 
private  boolean  mFinished ; 
private  UsbSerialPort  port  ;

// Grant permission to USB device 
PendingIntent  mPermissionIntent ; 
private  static  final  String  ACTION_USB_PERMISSION  =  "com.android.example.USB_PERMISSION" ;

// Interval shooting related 
private  boolean  isIntervalMode =  false ; 
private  boolean  isIntervalStat  =  false ; 
private  boolean  sendReq  =  false ;

Processing related to operation acceptance (onKeyDown (), onKeyUp ())

OnKeyDown () has been modified as follows to accept normal / interval shooting switching operation and interval shooting start / stop operation.

@Override 
            public  void  onKeyDown ( int  keyCode ,  KeyEvent  event )  { 
                // --------------- customized code --------------- 
                if  ( keyCode  ==  KeyReceiver . KEYCODE_CAMERA )  { 
                    / *
                     * To take a static picture, use the takePicture method.
                     * You can receive a fileUrl of the static picture in the callback.
                     * / 
                    An if  ( IsIntervalMode ) { 
                        an if  ( IsIntervalStat )  { 
                            IsIntervalStat  = false ; 
                        }  the else  { 
                            IsIntervalStat  = true ; 
                        } 
                        SENDREQ  =  true ; 
                    }  the else  { 
                        new new  TakePictureTask ( MTakePictureTaskCallback .) The execute (); 
                    } 
                }  the else  an if  ( keyCode  ==  KeyReceiver . KEYCODE_MEDIA_RECORD )  {
                    an if  ( IsIntervalMode )  { 
                        an if  ( IsIntervalStat )  { 
                            IsIntervalStat  = false ; 
                            SENDREQ  =  true ; 
                        } 
                        IsIntervalMode  =  false ; 
                        NotificationLedHide ( LedTarget . LEDs 7 ); 
                    }  the else  { 
                        IsIntervalMode  =  true ; 
                        NotificationLedShow ( LedTarget . LEDs 7 ); 
                    } 
                } 
                // - ---------------------------------------- 
            }

OnKeyUp () was left untouched.

        @Override 
        public  void  onKeyUp ( int  keyCode ,  KeyEvent  event )  { 
            / **
             * You can control the LED of the camera.
             * It is possible to change the way of lighting, the cycle of blinking, the color of light emission.
             * Light emitting color can be changed only LED 3.
             * / / / 
            Please remove code which was attached to SDK because it is unnecessary. 
            //notificationLedBlink(LedTarget.LED3, LedColor.BLUE, 1000); 
        }

Processing onResume ()

Processing related to serial communication initialization is described in onResume ().
The following three lines concerning the initialization of USB serial communication at the beginning are the arguments given from the argument “Process corresponding to vendor ID, product ID, USB device class” that we had prepared, then use that list after adding it to the device list. I will.

final  ProbeTable  probeTable  =  UsbSerialProber . getDefaultProbeTable (); 
        probeTable . addProduct ( 0x1546 , 0x01a7 , CdcAcmSerialDriver . class ); 
        List < UsbSerialDriver >  usb  =  new  UsbSerialProber ( probeTable ). findAllDrivers ( manager );

This is a modified version of the following code in README.md “4. Use it! Example code snippet:” of library " usb-serial-for-android ".

List < UsbSerialDriver > Usb = UsbSerialProber . GetDefaultProber . () FindAllDrivers ( Manager );

By doing this, when you use a device which is not defined in the library beforehand, you do not need to put your hand in the source code of the library side. To refer to the
library itself, please refer to this site and so on.

The baud rate setting for serial communication is the following line near the end of onResume ().
When changing the baud rate setting of the GPS / GNSS receiver, or when using different baud rates with other serial communication devices, please indicate the number appropriate for the device.

port . setParameters ( 9600 , 8 , UsbSerialPort . STOPBITS_ 1 , UsbSerialPort . PARITY_NONE );

Below, the entire code of onResume () is posted.

@Override 
    protected  void  onResume ()  { 
        Log . D ( "GNSS" ,  "M: onResume ()" );

        // --------------- added code --------------- 
        mFinished  =  true ;

        Find All Available // Drivers From Attached Devices. 
        UsbManager  Manager  =  ( UsbManager )  GetSystemService ( Context . USB_SERVICE ); 
        . // List <UsbSerialDriver> Usb = UsbSerialProber.GetDefaultProber () FindAllDrivers (Manager); 
        Final  ProbeTable  ProbeTable  =  UsbSerialProber . GetDefaultProbeTable ( ); 
        probeTable . addProduct ( 0x1546 , 0x01a7 , CdcAcmSerialDriver . class ); 
        List < UsbSerialDriver > usb  =  new  UsbSerialProber ( probeTable ). findAllDrivers ( manager );

        // 
        Check the number of devices recognized for debugging int  usbNum  =  usb . Size (); 
        Log . D ( "GNSS" , "usb num ="  +  usbNum   );

        If  ( Usb . IsEmpty ())  { 
            Log . D ( "GNSS" , "Usb Device Is Not Connect."   ); 
            NotificationLedBlink ( LedTarget . LED3 ,  LedColor . RED ,  1000 ); 
            // Return; 
            // Port = Null; 
        }  else  { 
            // Open a connection to the first available driver. 
            UsbSerialDriver  driver  =  usb . get ( 0 );

            // For granting permission to the USB device (Even if you thru the device, only giving a chance at the time of launching the application it is not necessary to give it a chance.) 
            MPermissionIntent  =  PendingIntent . GetBroadcast ( this ,  0 ,  new  Intent ( ACTION_USB_PERMISSION ),  0 ); 
            Manager . RequestPermission (  Driver . getDevice ()  ,  MPermissionIntent );

            UsbDeviceConnection  connection  =  manager . OpenDevice ( driver . GetDevice ()); 
            if  ( connection  ==  null )  { 
                // You probably need to call UsbManager.requestPermission (driver.getDevice (), ..) 
                // even after giving permission , become null that it is power Off-> on the left USB device is connected ... if able to re stabbed OK 
                NotificationLedBlink ( LedTarget . LED3 ,  LedColor . YELLOW ,  500 ); 
                Log . D ( "GNSS" , "M: Can not open usb device. \ N " );

                port  =  null ; 
            }  else  { 
                port  =  driver . getPorts (). get ( 0 );

                the try  { 
                    port . open ( connection ); 
                    //Port.SetParameters(115200, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE); 
                    port . setParameters ( 9600 ,  8 ,  UsbSerialPort . STOPBITS_1 ,  UsbSerialPort . PARITY_NONE );

                    mFinished  =  false ; 
                    start_read_thread ();

                }  Catch  ( IOException  e )  { 
                    . // Deal with error 
                    e . PrintStackTrace (); 
                    Log . D ( "GNSS" ,  "M: IOException" ); 
                    NotificationLedBlink ( LedTarget . LED 3 ,  LedColor . YELLOW ,  1000 ); 
                    // return ; 
                }  finally  { 
                    Log . d ( "GNSS" ,  "M: finally" ); 
                } 
            } 
        }
        // -----------------------------------------

        super . onResume (); 
    }

Process of onPause ()

OnPause () describes the termination of serial communication, and the cleaning-up completion process of the plug-in is described.

@Override 
    protected  void  onPause ()  { 
        // Do end processing 
        // close ();

        // --------------- added code --------------- 
        Log . d ( "GNSS" ,  "M: on Pause ()" ) ; 
        // clean up the case of the interval shooting Allowed 
        If  ( IsIntervalMode )  { 
            NotificationLedHide ( LedTarget . LED7 ); 
            If  ( IsIntervalStat )  { 
                IsIntervalStat  =  False ; 
                SendReq  =  True ; 
                Try  { 
                    // thread end waiting for just in case 
                    thread . Sleep ( 20 ); 
                }  catch  (InterruptedException  e ) { 
                    . // Deal with error 
                    e . PrintStackTrace (); 
                    Log . D ( "GNSS" ,  "T: InterruptedException" ); 
                    NotificationLedBlink ( LedTarget . LED 3 ,  LedColor . YELLOW ,  200 ); 
                } 
            } 
        }

        // Instructions to end the thread. I have not waited for completion. 
        mFinished  =  true ;

        // Do not 
        close if  you can not open the serial communication. If ( port  ! =  Null )  { 
            try  { 
                port . Close (); 
                Log . D ( "GNSS" ,  "M: onDestroy () port.close ) " ); 
                NotificationLedBlink ( LedTarget . LED 3 ,  LedColor . BLUE ,  200 ); 
            } catch ( IOException  e ) { 
                Log . d ( " GNSS " ,  " M: onDestroy () IOException " );
                NotificationLedBlink ( LedTarget . LED 3 ,  LedColor . RED ,  300 ); 
            } 
        }  the else  { 
            Log . d ( "GNSS" , "M: port = null \ n" ); 
        } 
        // ----------- ------------------------------

        super . onPause (); 
    }

Processing of added thread

serial reception, positioning log (TXT format) saving, interpretation of NMEA 0183, editing and sending of gpsInfo

It is a function that only developers can use, but processing is also made to create a file in the application area each time the plug-in is activated and save the raw data of the received positioning information.
The number of this file is restricted so that up to 20 files are saved in “int maxFileNum = 20;”. Please customize as necessary.
Although the extension of the file is “.txt”, setting it as “.ubx” makes it easier to handle a little from u-blox’s tool described later.

Where interval shooting is to be started, use the following code to set the shooting interval to 4 seconds (the shortest shooting interval of THETA V, the camera side will automatically act as the shortest shooting interval automatically if the shutter speed is longer than 4 seconds) Is set to unlimited (the number of sheets 0 setting means unlimited meaning).

Result = camera . SetIntervalParam ( 4 , 0 );

Below is an overview of thread processing.

 // read thread 
    public  void  start_read_thread () { 
        new  Thread ( new  Runnable () { 
            @Override 
            public  void  run ()  {

                FileOutputStream   out ;

                the try  { 
                    NotificationLedBlink ( LedTarget . LED 3 ,  LedColor . MAGENTA ,  500 ); 
                    Log . d ( "GNSS" ,  "Thread Start" );

                    Restriction On The // Number Of Log Files 
                    String []  Files  =  FileList (); 
                    Arrays . Sort ( Files ); 
                    Int  MaxFileNum  =  20 ; 
                    If  (  Files . Length  > =  MaxFileNum )  { 
                        For (  Int  I = 0 ;  I <=  ( files . length - maxFileNum );  i ++  ) { 
                            Log . d ( "GNSS",  "Delet file:"  +  files [ i ]  ); 
                            deleteFile ( files [ i ]); 
                        } 
                    }

                    Create Logfile // 
                    SimpleDateFormat   Df  =  New  SimpleDateFormat ( "YyyyMMdd_HHmmss" ); 
                    Final  Date  Date  =  New  Date ( System . CurrentTimeMillis ()); 
                    String  FileName  =  "GNSS_Log_"  Tasu  Df . Format ( Date )  Tasu  ".Txt" ; 
                    Out  =  openFileOutput ( FileName , MODE_PRIVATE | MODE_APPEND );

                    // gpsInfo editing buffer 
                    String  Lat  =  "" ; 
                    String  Lng  =  "" ; 
                    String  _Altitude  =  "" ; 
                    String  _DateTimeZone  =  "" ; 
                    String  UtcYYYYMMDD  =  "" ; 
                    String  UtcHHMMSS  =  "" ;

                    while ( mFinished == false ) {

                        // serial communication receiving polling unit 
                        byte  buff []  =  new new  byte [ 256 ]; 
                        int  num  =  port . Read ( buff ,  buff . Length ); 
                        an if  (  num  >  0  )  { 
                            String  RcvStr  =  new new  String ( buff ,  0 ,  num ); 
                            String []  SplitSentence  =  RcvStr . Split ( "," ,  0);

                            Log . D ( "GNSS" ,  RcvStr ); 
                            Out . Write ( Buff , 0 ,  RcvStr . Length ());

                            // [RMC sentence] 
                            // 
                            Year / month / date is only in RMC sentence // reliability, latitude, longitude, time is overlapped with GGA sentence 
                            // no altitude 
                            // received before GGA sentence 
                            if  (  splitSentence [ 0 ]. ContentEquals ( "$ GPRMC" )  Andoando  ( SplitSentence . Length  ==  13 )  )  { 
                                // GpsInfo: UTC date of editing 
                                If  (  SplitSentence [ 9 .] Length ()  ==  6  )  { 
                                    UtcYYYYMMDD  =  " 20 "  +  splitSentence [ 9 ].substring ( 4 ,  6 )  +  ":"  +  SplitSentence [ 9 ]. substring ( 2 ,  4 )  +  ":"  +  SplitSentence [ 9 .] substring ( 0 ,  2 ); 
                                    //Log.D("GNSS "," YY: MM: DD (UTC) = "+ utcYYMMDD); 
                                }  else  { 
                                    utcYYYYMMDD  =  " " ; 
                                } 
                            }

                            // Execute setGpsInfo if reliable location information 
                            / / [GGA sentence] 
                            // UTC: used 
                            // latitude: ddmm.mmmmm is separated dd + (mm.mmmmm / 60) 
                            // N / S: 
                            Google 
                            north latitude as it is, south latitude giving minus // longitude: dddmm.mmmmm is separated Google draft map format with ddd + (mm.mmmmm / 60) // E / W: east long as it is, west long gives a minus 
                            // locate Quality: 0 can not be measured, 1or2 can be measured if it is 
                            used // number of satellites used: unused 3 altitude accuracy is not high 
                            / horizontal accuracy drop rate 
                            / 
                            unused // antenna elevation height: use // above unit: m is meters 
                            // geoid height: unused 
                            // above unit: m in meters 
                            reference point for the // DGPS not use the blank 
                            // * checksum: do not check this time 
                            if  (  splitSentence [ 0 ]. contentEquals ( "$ GPGGA" )  &&  ( splitSentence .length  ==  15 )  )  { 
                                // authenticity-checking 
                                an if  (  SplitSentence [ 6 ]. contentEquals ( "1" )  ||  SplitSentence [ 6 ]. contentEquals ( "2" )  )  { 
                                    NotificationLedBlink ( LedTarget . LED 3 ,  LedColor . GREEN ,  500 ); 
                                    // GpsInfo: Lat of editing 
                                    Double  LatTop  =  Double . valueOf (  SplitSentence[ 2 ]. Substring ( 0 , 2 )  ); 
                                    the Double  LatEnd  =  the Double . ValueOf (  SplitSentence [ 2 ]. Substring ( 2 , SplitSentence [ 2 ]. Length ())  ); 
                                    the Double  LatResult  =  LatTop  +  ( LatEnd / 60 )  ; 
                                    lat  =  String . format ( "% 02.06 f" ,  latResult); 
                                    An if  (  SplitSentence [ 3 .] ContentEquals ( "S" )  )  { 
                                        lat  =  "-"  +  lat  ; 
                                    }

                                    // GPSInfo: lng editing 
                                    the Double  LngTop  =  the Double . ValueOf (  SplitSentence [ 4 .] Substring ( 0 , 3 )  ); 
                                    the Double  LngEnd  =  the Double . ValueOf (  SplitSentence [ 4 .] Substring ( 3 , SplitSentence [ 4 .] Length ( ))  ); 
                                    Double  lngResult  =  lngTop  +  ( lngEnd / 60)  ; 
                                    Lng  =  String . Format ( "% 02.06F" ,  LngResult ); 
                                    an if  (  SplitSentence [ 5 .] ContentEquals ( "W" )  )  { 
                                        lng  =  "-"  +  lng  ; 
                                    }

                                    // gpsInfo: Edit 
                                    _altitude  _ altitude =  splitSentence [ 9 ];  // This time do not check the range and use as it is

                                    // gpsInfo: UTC hours and minutes After editing _dateTimeZone after obtaining seconds 
                                    if  ( splitSentence [ 1 ]. length ()  ==  9 )  { 
                                        utcHHMMSS  =  splitSentence [ 1 ]. substring ( 0 , 2 )  +  ":"  +  splitSentence [ 1 ] substring ( 2 , 4 )  +  ":"  +  splitSentence [ 1 ]. substring ( 4 , 6 )  ; 
                                    } 
                                    _dateTimeZone  =  utcYYYYMMDD  +  ""  +  utcHHMMSS  +  "+ 09: 00" ;  // In this example, the time zone is fixed to JST. 
                                    // Log.d("GNSS "," UTC = "+ _dateTimeZone);

                                    // editing of debug table information 
                                    String  LogStr  =  "Lat ="  Tasu  Lat  Tasu ", Lng ="  Tasu  Lng  Tasu  ", Height ="  Tasu  _Altitude  Tasu  ", DateTime ="  Tasu  _DateTimeZone  Tasu  "\ N" ; 
                                    Log . D ( "GNSS" ,  "gpsInfo ="  +  logStr );

                                    // gpsInfo setting 
                                    HttpConnector  camera  =  new  HttpConnector ( "127.0.0.1 : 
                                    8080 " ); String  setGpsInfoResult  =  camera . setGpsInfo ( lat ,  lng ,  _altitude ,  _dateTimeZone ); 
                                    Log . d ( "GNSS" ,  "setGpsInfoResult:"  +  setGpsInfoResult ) ; 
                                }  else  { 
                                    notificationLedBlink ( LedTarget . LED 3 ,  LedColor . MAGENTA,  500 ); 
                                } 
                            } 
                        } 
                        // Sleep 10 ms to prevent polling from becoming too frequent 
                        Thread . Sleep ( 10 );

                        // execution of interval shooting start / stop instruction 
                        an if  ( SENDREQ  ==  true ) { 
                            String  the Result  ; 
                            HttpConnector  camera  =  new new  HttpConnector ( "127.0.0.1:8080" ); 
                            an if  (  IsIntervalStat  )  { 
                                the Result  =  camera . SetIntervalParam ( 4 ,  0 ); 
                                Log . D ( "GNSS" ,  "T: Camera.SetIntervalParam () ="  Tasu  Result ); 
                                Result  =  Camera .StartCapture ( "interval" ); 
                                Log . d ( "GNSS" ,  "T: Camera.StartCapture () ="  +  the Result ); 
                                NotificationLedShow ( LedTarget . LED 6 ); 
                            }  the else  { 
                                the Result  =  camera . StopCapture (); 
                                Log . d ( "GNSS" ,  "T: camera.stopCapture () ="  +  Result ); 
                                notificationLedHide ( LedTarget . LED 6 ); 
                            } 
                            sendReq  = false ; 
                        } 
                    } 
                    out . close ();

                }  Catch  ( IOException  e )  { 
                    . // Deal with error 
                    e . PrintStackTrace (); 
                    Log . D ( "GNSS" ,  "T: IOException" ); 
                    NotificationLedBlink ( LedTarget . LED 3 ,  LedColor . YELLOW ,  100 ); 
                }  catch  ( InterruptedException  e )  { 
                    . // Deal with error 
                    e . printStackTrace (); 
                    Log . d ("GNSS" ,  "T: InterruptedException" ); 
                    NotificationLedBlink ( LedTarget . LED 3 ,  LedColor . YELLOW ,  200 ); 
                }  a finally  { 
                    Log . D ( "GNSS" ,  "T: a finally" ); 
                } 
            } 
        .}) Start () ; 
    }

Next

Using the GPS Plug-in

Tip: Use THETA API to add GPS information to Image

You can acquire GPS information from an external GPS module and attach it to the THETA image metadata using the RICOH API setOptions, gpsInfo.

https://developers.theta360.com/en/docs/v2.1/api_reference/options/gps_info.html

Short Example

image

Full Example for Plug-in

Is there a camera API for the Theta X for GNSS support? Does it still require the use of the usb-serial-for-android library or is there a more preferred method?

The THETA X has built in GPS.

See this.

Notice of website closure

Let me know if you have any questions.

There’s nothing plugged into the THETA. The cable in the video is just for electrical power during testing on my desk. This will work walking around with the camera powered from battery.

Is there any way to get HDOP data from the internal GPS? I’d like to create a plug-in that only takes interval photos when the GPS accuracy is within a certain threshold (i.e. not all over the place when I’m under tree canopy cover).

P.S. It would be awesome if Ricoh could provide a device filter for their developer API documentation. Trying to filter through the relevant methods for the X is bit tedious.

I am not familiar with the HDOP data.

Can a normal Android phone using an internal GPS access the GPS data using the Android SDK?

Does this Stackoverflow question answer your question?

the THETA X is an Android 10 device.