Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Mobile / Android

Creating an APRS Tracker & Automated Camera with an Android Phone

4.91/5 (8 votes)
27 Apr 2011CPOL4 min read 50.6K   3.3K  
Take pictures and broadcast GPS location on a set schedule, useful in balloon payloads or as a standalone tracker

Introduction

This is a project for an Android phone that takes pictures and broadcasts the phone GPS coordinates using the amateur radio APRS infrastructure. I'm using it as a backup tracker for a high altitude balloon project, but it can be used for a couple things such as setting in one place and storing time lapse photos, or keeping track of where the phone is graphically on a map.

For example, I set it in my backyard because I knew ducks were visiting periodically and was able to get this picture:

duck.jpg

And here is a picture of using aprs.fi to track the phone's location as it moves around (ducks were not involved in this one):

Capture.JPG

Background

APRS is an amateur radio based technology for communicating information using packet radio. There is an internet infrastructure for it as well (not using a radio at all) which is convenient because you get all the mapping and tracking amateur radio infrastructure such as aprs.fi for free. If you aren't a licensed amateur radio operator, you won't be able to use this code as-is and will have to modify how it posts GPS information and would need to implement the mapping yourself. It is interesting and fairly easy to get an amateur radio license though so I would encourage you to go that route.

Using the Code

The attached code is an Eclipse project that targets Android 2.1. It will also work on Android 1.5 if you want to target that version as well. I upgraded it just to have more exposed camera functionality for setting picture quality and other attributes. There are three main pieces to the project:

  1. Retrieving GPS coordinates and altitude information
  2. Taking and storing a picture from the phone camera on an SD card
  3. Submitting the GPS information through the existing APRS infrastructure

Additionally, there is also some code to save the information entered so it doesn't have to be re-typed every time. The main reason I added this is for the callsign and passcode used so the GPS information can be sent to the APRS servers. If you aren't a licensed amateur radio operator, you won't have anything to put here and will have to either change the code to post to your own server (and then display it on a map) or go get yourself an amateur radio license.

I am mostly a .NET developer during the day so setting up Eclipse and Android was a new thing for me. So if you are an experienced Java developer and see any strangeness in the Java code, that is why! I found the process to be pretty straightforward and very similar to using Visual Studio for .NET Micro projects. For the most part, things just work and you can debug on the device itself which is very nice.

  1. Retrieving GPS coordinates and altitude information:

    All you need for GPS location and altitude is a reference to the location manager. The rest of the code is just formatting it for the APRS infrastructure.

    Java
    Location location = locationManager
       .getLastKnownLocation(LocationManager.GPS_PROVIDER);
    
    String latitude = 
          getAsDegreesMinutesSeconds(location.getLatitude(), "N", "S");
    String longitude = 
          getAsDegreesMinutesSeconds(location.getLongitude(), "E", "W");
    String altitude = 
          ExactNumDigits(((int)location.getAltitude()) + "", 6);
  2. Taking and storing a picture from the phone camera on an SD card:

    This took lots of trial and error to get right, but appears simple once it is done. Make sure you start a preview before taking a picture (though you don't have to show it apparently) and always clean up once done so if the user switches from your app to a camera based app, they can still use the camera.

    Java
    public void takePicture() {
      try {
          toastText("Taking picture");
          Camera camera = Camera.open();
          camera.setErrorCallback(errorCallback);
          
          try {
           camera.startPreview();
              camera.takePicture(null, null, jpegCallback);
          } finally {
              camera.stopPreview();
              camera.release();
              camera = null;
          }
      } catch(Exception ex) {
       toastText(ex.toString());
      }
    }
    
     Camera.ErrorCallback errorCallback = new Camera.ErrorCallback() {
      public void onError(int arg0, Camera arg1) {
       toastText("Camera error: " + arg0);
      }
     };
        
        // Handles data for jpeg picture
        PictureCallback jpegCallback = new PictureCallback() { // <8>
          public void onPictureTaken(byte[] data, Camera camera) {
          String filePath = String.format("/sdcard/Pics/%1$s.jpg", 
                        new SimpleDateFormat("yyyy.MM.dd.HH.mm.ss").format(new Date()));
          toastText("Writing " + data.length + " bytes to " + filePath);
             FileOutputStream outStream = null;
             try {
               // Write to SD Card
               outStream = new FileOutputStream(filePath); 
               outStream.write(data);
               outStream.close();
             } catch (Exception e) {
              toastText(e.toString());
             }
          }
        };
  3. Submitting the GPS information through the existing APRS infrastructure:

    For more information, see the APRS standard for how information should be submitted but it is just a normal TCP/IP connection, sending and receiving strings between the client and the server. If the callsign/passcode don't match up, the server will not accept the position report and you won't see it on sites such as aprs.fi.

    Java
    Socket socket = null;
    try {
     socket = new Socket("texas.aprs2.net", 14580); 
     BufferedReader inReader = new BufferedReader(
      new InputStreamReader(socket.getInputStream())
     );
    
     String input = inReader.readLine();
     
     PrintWriter out = new PrintWriter(
      new BufferedWriter(
       new OutputStreamWriter(socket.getOutputStream())
      ), 
      true
     );  
    
     String loginText = 
      String.format("user %1$s pass %2$s -1 vers APRSAndroid 1.0_00 filter m/5", 
      callSign, 
      passCode
     );
     out.println(loginText);  
    
     input = inReader.readLine();
     if(!input.startsWith(String.format("# logresp %1$s verified", callSign)))
      throw new Exception("Unable to verify call sign/pass code");
     
     String locationString = 
         String.format("%1$s>APRS,TCPIP*:=%2$s/0%3$s$/A=%4$sAPRSAndroid", 
          callSign, 
       latitude, 
       longitude, 
       altitude
      );
     out.println(locationString);  
    
     toastText(
      String.format("Sent location %1$s/%2$s /A=%3$s for %4$s", 
      latitude, 
      longitude, 
      altitude, 
      callSign
     ));
    } catch (Exception e) {
     toastText("Unable to connect: " + e.getMessage());
    }
    finally {
     try {
      if(socket != null) {
       socket.close();
      }
     } catch (IOException e1) { }
    }

Summary

So that is all that is needed to have a $100 device that can broadcast GPS position and automatically take pictures! The Android device I used is an AT&T Backflip, easily procurable off of Ebay and something I really enjoy using. I think this is a nice and easy way of automating pictures similar to using CHDK but with the ability to debug on the device and also use the phone's additional capabilities such as GPS and network access. Below is a screenshot of the interface - it won't win me any UI design awards but gives enough control over all the features.

Capture2.JPG

Enjoy!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)