Hackster is hosting Hackster Holidays, Ep. 6: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Monday!Stream Hackster Holidays, Ep. 6 on Monday!
MassimilianoMichele Valentini
Published © Apache-2.0

Android GPS and IMU logger with The Tactigon

Connect The Tactigon Arduino board to a GROVE GPS breakout board and send position to an Android device for portable data logging

AdvancedFull instructions provided5 hours1,347

Things used in this project

Hardware components

Android device
Android device
with Bluetooth Low Energy
×1
The Tactigon One
The Tactigon One
×1
Seeed Studio GROVE GPS
×1

Software apps and online services

Processing
Arduino IDE
Arduino IDE

Story

Read more

Schematics

fritzing_RL18Ga5i7y.jpg

Code

GPS.ino

Arduino
/**
  $GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47

  Where:
     GGA          Global Positioning System Fix Data
     123519       Fix taken at 12:35:19 UTC
     4807.038,N   Latitude 48 deg 07.038' N
     01131.000,E  Longitude 11 deg 31.000' E
     1            Fix quality: 0 = invalid
                               1 = GPS fix (SPS)
                               2 = DGPS fix
                               3 = PPS fix
            4 = Real Time Kinematic
             5 = Float RTK
                               6 = estimated (dead reckoning) (2.3 feature)
             7 = Manual input mode
             8 = Simulation mode
     08           Number of satellites being tracked
     0.9          Horizontal dilution of position
     545.4,M      Altitude, Meters, above mean sea level
     46.9,M       Height of geoid (mean sea level) above WGS84
                      ellipsoid
     (empty field) time in seconds since last DGPS update
     (empty field) DGPS station ID number
      47          the checksum data, always begins with
*/

#include <tactigon_led.h>
#include <tactigon_BLE.h>
#include <tactigon_IMU.h>
#include <tactigon_UserSerial.h>
#include <tactigon_IO.h>
#include <stdio.h>

char bufferGPS[92];                   // buffer array for data receive over serial port
int count = 0;                              // counter for buffer array
uint8_t g_bbb[15];
boolean bufferFull = false;

//RGB LEDs
T_Led rLed, bLed, gLed;
T_ACC accMeter;
T_AccData accData;

T_QUAT qMeter;
T_QData qData;

//BLE Manager, BLE Characteristic and its UUID
T_BLE bleManager;
UUID uuid;
T_BLE_Characteristic bleChar;




//UART
T_UserSerial tSerial;

//GPIO
T_GPP gpp4;

//Used for LEDs cycle
int  ticksLed, stp;


void setup() {
  //Serial.begin(115200);
  rLed.init(T_Led::RED);
  gLed.init(T_Led::GREEN);
  bLed.init(T_Led::BLUE);

  rLed.off();
  gLed.off();
  bLed.off();

  //init role
  bleManager.InitRole(TACTIGON_BLE_PERIPHERAL);
  // bleManager.setName("TTGPS");
  //uuidIMU.set("6039d4f2-080c-11e8-ba89-0ed5f89f718b");
  uuid.set("6039d2a4-080c-11e8-ba89-0ed5f89f718b");

  bleChar = bleManager.addNewChar(uuid, 15);
  // bleIMUChar = bleManager.addNewChar(uuidIMU, 14);

  //init gpps
  gpp4.init(T_GPP::GPP4, T_GPP::GPP_OUT);

  //init user serial
  gpp4.write(1);
  tSerial.init(T_UserSerial::B_9600);
  tSerial.setRxByteCB(cbUartRxByte);
  tSerial.setRxLineCB(cbUartRxLine);
}

/*----------------------------------------------------------------------*/
void cbUartRxByte(uint8_t bb) {
  bufferGPS[count++] = bb;    // writing data into array
  if ((char)bb == '\n' /*|| count == 63*/ ) {
    bufferFull = true;
  }
}

/*----------------------------------------------------------------------*/
void cbUartRxLine(const uint8_t *pLine, uint8_t len) {

}

void IMUUpdate() {
  //unsigned char buffData[14];
  //get acc data
  accData = accMeter.getAxis();

  //get quaternions data
  qData = qMeter.getQs();

  //prepare buffer
  memcpy(&g_bbb[0], &qData.q0, 2);
  memcpy(&g_bbb[2], &qData.q1, 2);
  memcpy(&g_bbb[4], &qData.q2, 2);
  memcpy(&g_bbb[6], &qData.q3, 2);

  memcpy(&g_bbb[8], &accData.x, 2);
  memcpy(&g_bbb[10], &accData.y, 2);
  memcpy(&g_bbb[12], &accData.z, 2);
  g_bbb[14] = 0x55;
  //update ble characteristic
  bleChar.update(g_bbb);
}


void AnglesUpdate() {
  qData = qMeter.getQs();
  memcpy(&g_bbb[0], &qData.roll, sizeof(float));
  memcpy(&g_bbb[4], &qData.pitch, sizeof(float));
  memcpy(&g_bbb[8], &qData.yaw, sizeof(float));

  g_bbb[14] = 0x55;
  //update ble characteristic
  bleChar.update(g_bbb);
}

void parseBuffer() {
  if (StrContains(bufferGPS, "GPGGA")) {

    bufferGPS[63] = '\0';
    /**
      $GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47
      $GPGGA,091332.000,4531.9253,N,00929.9413,E,1,9,0.78,127.0,M,48.
    */
    int ret;
    float timestampF, latF, lonF = 0;
    char timestamp[11], lat[10], latS[2], lon[11], lonS[2], crap[64];
    //Serial.write(bufferGPS, 63);

    if ( sscanf(&bufferGPS[7], " %[^','], %[^','], %[^','], %[^','], %[^','], %s", timestamp, lat, latS, lon, lonS, crap) > 5) {
      // if ( sscanf(&bufferGPS[7], "%f,%f,%c,%f,%c,%s", &timestampF, &latF, latS, &lonF, lonS, crap) > 5 ) {
      Serial.write(timestamp, 10);
      Serial.println();

      Serial.write(lat, 9);
      Serial.write(latS, 1);
      Serial.println();

      Serial.write(lon, 10);
      Serial.write(lonS, 1);
      Serial.println();

      timestampF = atof (timestamp);
      latF = atof (lat);
      lonF = atof (lon);

      rLed.on();
      gLed.on();
      bLed.on();

      memcpy(&g_bbb[0], &latF, sizeof(float));
      memcpy(&g_bbb[4], &latS[0], 1);
      memcpy(&g_bbb[5], &lonF, sizeof(float));
      memcpy(&g_bbb[9], &lonS[0], 1);
      memcpy(&g_bbb[10], &timestampF, sizeof(float));
      g_bbb[14] = 0xaa;
      bleChar.update(g_bbb);
    }
  }
  clearBufferArray();
  count = 0;
}


void loop() {
  int ret;
  float timestampF, latF, lonF = 0;
  //char timestamp[11], lat[10], latS[2], lon[11], lonS[2], crap[64];
  if (bufferFull) {
    parseBuffer();
    bufferFull = false;
  }

  //Cycle rgb leds
  if (GetCurrentMilli() >= (ticksLed + (1000 / 1))) {
    AnglesUpdate();

    ticksLed = GetCurrentMilli();
    if (stp == 0) {
      rLed.on();
      gLed.off();
      bLed.off();
    }
    else if (stp == 1) {
      rLed.off();
      gLed.off();
      bLed.on();
    }
    else if (stp == 2) {
      rLed.off();
      gLed.on();
      bLed.off();
    }
    stp = (stp + 1) % 3;

    //sprintf(bufferGPS, "$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47");
    //ret = sscanf(&bufferGPS[7], "%f,%f,%c,%f,%c,%s", &timestampF, &latF, latS, &lonF, lonS,crap);

    //    sprintf(bufferGPS, "123.45");
    //    ret = sscanf(bufferGPS, "%lf", &timestampF);
    //
    //    Serial.println(ret);
    //    Serial.write(bufferGPS, 20);

  }

}


void clearBufferArray()     {                // function to clear buffer array
  for (int i = 0; i < count; i++) {
    bufferGPS[i] = NULL;
  }                      // clear all index of array with command NULL
}


char StrContains(const char *str, const char *sfind) {
  char found = 0;
  char index = 0;
  char len;

  len = strlen(str);

  if (strlen(sfind) > len) {
    return 0;
  }
  while (index < len) {
    if (str[index] == sfind[found]) {
      found++;
      if (strlen(sfind) == found) {
        return 1;
      }
    }
    else {
      found = 0;
    }
    index++;
  }

  return 0;
}

V7.rar

Arduino
Full source code
No preview (download only).

BLEGPS.pde

Processing
/************************************/
/* The Tactigon GPS and IMU Logging */
/* V0.7 - Michele Valentini         */
/************************************/


import blepdroid.*;
import blepdroid.BlepdroidDevice;
import android.os.Bundle;
import android.content.Context;
import java.util.UUID;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import android.location.Location;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

Buffer buffer;
int bufferSize = 100; 
BlepdroidDevice device1;
Blepdroid blepdroid;
int textSizeVal = 60;
boolean allSetUp = false;
boolean targetCharacteristicFound = false;
float lat, lon, timestamp;
char latS, lonS;
float roll, pitch, yaw;
public static String deviceName = "TTGPS";
private SimpleDateFormat sdf;
private String filename;
private String path = "/sdcard/TheTactigon/";
public static String TACTIGON_QUAT_CHAR_STRING = "6039d2a4-080c-11e8-ba89-0ed5f89f718b";
public static UUID TACTIGON_QUAT_UUID = UUID.fromString(TACTIGON_QUAT_CHAR_STRING);

private GPSData lastGPS;
void setup() {

  lat = 0;
  lon= 0;
  timestamp = 0;
  latS = ' ';
  lonS = ' ';
  roll = 0;
  pitch = 0;
  yaw = 0;
  sdf  = new SimpleDateFormat();
  sdf.applyPattern("yyyyMMdd_HHmmss");

  filename =  "TheTactigon_"+getTime()+"_.kml";
  buffer = new Buffer(bufferSize, filename, path);
  fullScreen();
  smooth();
  blepdroid = new Blepdroid(this);
}

void draw() {
  if (allSetUp) {
    background(10);
    textSize(textSizeVal/3);
    textAlign(CENTER, CENTER);
    text("(DMm)", width/2, height/3-(3*textSizeVal));
    textSize(textSizeVal);
    textAlign(CENTER, CENTER);
    text(getLatString(), width/2, height/3-(2*textSizeVal));
    textAlign(CENTER, CENTER);
    text(getLonString(), width/2, height/3);
    textAlign(CENTER, CENTER);
    text(getTimestampString(), width/2, height/3+(2*textSizeVal));
    textAlign(CENTER, CENTER);
    text(getRollString(), width/2, (2*height/3)-(2*textSizeVal));
    textAlign(CENTER, CENTER);
    text(getPitchString(), width/2, (2*height/3));
    textAlign(CENTER, CENTER);
    text(getYawString(), width/2, (2*height/3)+(2*textSizeVal));
    textSize(textSizeVal/2);
    textAlign(CENTER, CENTER);
    text(path+filename, width/2, (2*height/3)+(3*textSizeVal));
  } else {
    background(100);
    textSize(textSizeVal*2);
    textAlign(CENTER, CENTER);
    text("TAP TO", width/2, height/2-(textSizeVal));
    text("CONNECT", width/2, height/2+(textSizeVal));
  }
}

void mousePressed() {
  if (targetCharacteristicFound == false) {
    println(" scan !");
    blepdroid.scanDevices();
  } else {
    println(" Connected " );
  }
}
void stop() {
  buffer.close();
  super.stop();
} 

void exit() {
  println("exiting");
  super.exit();
}

private String getLatString() {
  return "LAT: ".concat(Utils.NMEAtoDMm(lat)).concat(Character.toString(latS));
  // return Float.toString(lat).concat(Character.toString(latS));
}
private String getLonString() {
  return "LON: ".concat(Utils.NMEAtoDMm(lon)).concat(Character.toString(lonS));
  // return Float.toString(lon).concat(Character.toString(lonS));
}
private String getTimestampString() {
  return ""+timestamp+" GMT";
}
private String getRollString() {
  return "Roll: ".concat(String.format("%.2f", roll)).concat("");
}
private String getPitchString() {
  return "Pitch: ".concat(String.format("%.2f", pitch)).concat("");
}
private String getYawString() {
  return "Yaw: ".concat(String.format("%.2f", yaw)).concat("");
}

// get the date and time as a String:
private String getTime() {
  return sdf.format(new Date());
}


void onDeviceDiscovered(BlepdroidDevice device) {
  println("discovered device " + device.name + " address: " + device.address + " rssi: " + device.rssi );

  if (device.name != null && device.name.equals(deviceName)) {
    println("Device Found");

    if (blepdroid.connectDevice(device)) {
      println(" connected!");

      device1 = device;
    } else {
      println(" couldn't connect target device ");
    }
  }
}

void onServicesDiscovered(BlepdroidDevice device, int status) {

  HashMap<String, ArrayList<String>> servicesAndCharas = blepdroid.findAllServicesCharacteristics(device);
  for ( String service : servicesAndCharas.keySet()) {
    print( service + " has " );

    // this will list the UUIDs of each service, in the future we're going to make
    // this tell you more about each characteristic, e.g. whether it's readable or writable
    //println( servicesAndCharas.get(service));
    for (String charact : servicesAndCharas.get(service)) {
      print( " charact: " + charact);



      if (charact.equals(TACTIGON_QUAT_CHAR_STRING)) {
        targetCharacteristicFound = true;
        print( " target QUAT characteristic found! ");
        println("Registered UUID: " + TACTIGON_QUAT_UUID);
        blepdroid.setCharacteristicToListen(device, TACTIGON_QUAT_UUID);
      }
    }
  }
  // we want to set this for whatever device we just connected to
  //blepdroid.setCharacteristicToListen(device, RFDUINO_UUID_RECEIVE);

  allSetUp = true;
}
void onBluetoothRSSI(BlepdroidDevice device, int rssi) {
  println(" onBluetoothRSSI " + device.address + " " + Integer.toString(rssi));
}

void onBluetoothConnection( BlepdroidDevice device, int state) {
  blepdroid.discoverServices(device);
}

void onCharacteristicChanged(BlepdroidDevice device, String characteristic, byte[] data) {
  println("XXX onCharacteristicChanged " + characteristic);
  /** Aggiornare dati nuovi **/
  byte[] IDMexA = new byte[1];
  System.arraycopy(data, 14, IDMexA, 0, 1);



  if (IDMexA[0] == (byte) 0xAA) {
    println("  GPS");
    byte[] latA = new byte[4];
    byte[] latSA = new byte[1];
    byte[] lonA = new byte[4];
    byte[] lonSA = new byte[1];
    byte[] timestampA = new byte[4];
    System.arraycopy(data, 0, latA, 0, 4);
    System.arraycopy(data, 4, latSA, 0, 1);
    System.arraycopy(data, 5, lonA, 0, 4);
    System.arraycopy(data, 9, lonSA, 0, 1);
    System.arraycopy(data, 10, timestampA, 0, 4);
    lat = ByteBuffer.wrap(latA).order(ByteOrder.LITTLE_ENDIAN).getFloat();
    lon = ByteBuffer.wrap(lonA).order(ByteOrder.LITTLE_ENDIAN).getFloat();
    timestamp = ByteBuffer.wrap(timestampA).order(ByteOrder.LITTLE_ENDIAN).getFloat();
    latS = (char)latSA[0];
    lonS = (char)lonSA[0];
    println("   " + lat + " " + latS + " " + lon + " " + lonS + " " + timestamp);
    lastGPS = new GPSData(lat, latS, lon, lonS, timestamp);
    buffer.addData(lastGPS);
  } else if (IDMexA[0] == 0x55) {
    println("  IMU");
    byte[] rollA = new byte[4];
    byte[] pitchA = new byte[4];
    byte[] yawA = new byte[4];
    System.arraycopy(data, 0, rollA, 0, 4);
    System.arraycopy(data, 4, pitchA, 0, 4);
    System.arraycopy(data, 8, yawA, 0, 4);
    roll = ByteBuffer.wrap(rollA).order(ByteOrder.LITTLE_ENDIAN).getFloat();
    pitch = ByteBuffer.wrap(pitchA).order(ByteOrder.LITTLE_ENDIAN).getFloat();
    yaw = ByteBuffer.wrap(yawA).order(ByteOrder.LITTLE_ENDIAN).getFloat();

    roll = (roll * 180)/(float)Math.PI;

    pitch =  (pitch * 180)/(float)Math.PI;

    yaw =  (yaw * 180)/(float)Math.PI;

    println("   Roll: "+roll+" Pitch: "+ pitch + " Yaw: "+yaw);
    if (lastGPS == null) {
      println("lastGPS == null");
    } else {
      lastGPS.addIMUData(new IMUData(roll, pitch, yaw));
      println("lastGPS.addIMUData()");
    }
  } else
  {
    println("  UNKNOWN: " + IDMexA[0]);
  }
}

void onDescriptorWrite(BlepdroidDevice device, String characteristic, String data) {
  println(" onDescriptorWrite " + characteristic + " " + data);
}

void onDescriptorRead(BlepdroidDevice device, String characteristic, String data) {
  println(" onDescriptorRead " + characteristic + " " + data);
}

void onCharacteristicRead(BlepdroidDevice device, String characteristic, byte[] data) {
  println(" onCharacteristicRead " + characteristic + " " + data);
}

void onCharacteristicWrite(BlepdroidDevice device, String characteristic, byte[] data) {
  println(" onCharacteristicWrite " + characteristic + " " + data);
}

Buffer.pde

Processing
import java.util.*;
import java.io.FileOutputStream;
import android.content.Context;
import android.os.Environment;
import java.io.*;


public class Buffer {
  private int size;
  private String path;
  private String filename;
  private PrintWriter out;
 
  private List<GPSData> DataList = new ArrayList<GPSData>();

  public Buffer(int size) {
    this.size = size;
    this.filename="TheTactigonGPS.txt";
    this.path = "//sdcard//TheTactigon//";
    this.open();
   
  }
  public Buffer (int size, String filename) {
    this.size = size;
    this.filename = filename;
    println(filename);
    this.path="//sdcard//TheTactigon//";
        this.open();
  }

  public Buffer(int size, String filename, String path) {
    this.size = size;
    this.path = path;
    this.filename=filename;
        this.open();
  }
  
  public void open(){
    if(OpenFile()){
      //Write the tags to open
    out.println("<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n<Document>\n\t<name>"+this.filename+"</name>\n");
        out.flush();
    out.close();
    }

    
  }
  public void close() {
    //Write the tags to close
    if (OpenFile()){
      out.println("</Document>\n</kml>");
          out.flush();
    out.close();
    }

  }

  public void addData(GPSData data) {
    if (DataList.size()<size) {
      DataList.add(data);
    } else {
      DataList.add(data);
      //Write to path
      if (OpenFile()) {
        for (GPSData d : DataList) {
          out.println(d.toKML());
        }
        out.flush();
        out.close();
        DataList.clear();
      }
    }
  }

  private void createFile(File f) {
    File parentDir = f.getParentFile();
    try {
      parentDir.mkdirs(); 
      f.createNewFile();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }

  private boolean OpenFile() {
    boolean fileOpened = false;
    try {

      File f = new File(dataPath(path+filename));
      File dir = new File(dataPath(path));
      if (!dir.exists()) {
        dir.mkdir();
      }
      if (!f.exists()) {  
        createFile(f);
      }

      try {
        out = new PrintWriter(new BufferedWriter(new FileWriter(f, true)));
       // out.println("Open!!###\n");
        fileOpened = true;
        //out.close();
      }
      catch (IOException e) {
        e.printStackTrace();
      }
    }  
    catch(Exception exc) {
      print("Eccezione apertura file! " + exc.getMessage());
    }
    return fileOpened;
  }

}

Data.pde

Processing
public interface Data {
  public String toKML();
}

GPSData.pde

Processing
public class GPSData implements Data{

  private float altitude;
  private float lat;
  private float lon;
  private float timestamp;
  private char latS;
  private char lonS;

  private List<Data> IMU;
  public GPSData(float lat, char latS, float lon, char lonS, float timestamp) {

    IMU = new ArrayList<Data>();
    this.latS = latS;
    this.lat = lat;
    this.lonS = lonS; 
    this.lon = lon;
    this.timestamp = timestamp;
    this.altitude = 0;
  }
  public GPSData(float lat, char latS, float lon, char lonS, float timestamp, float altitude) {
    IMU = new ArrayList<Data>();
    this.latS = latS;
    this.lat = lat;
    this.lonS = lonS; 
    this.lon = lon;
    this.timestamp = timestamp;
    this.altitude=altitude;
  }
  public void addIMUData(IMUData imu) {
    IMU.add(imu);
  }



  public float getDDLat() {
    float ret;
    ret = Utils.NMEAtoDD(lat);
    if (latS == 'S') {
      ret = -(ret);
    }
    return ret;
  }
  public float getDDLon() {
    float ret;
    ret = Utils.NMEAtoDD(lon);
    if (lonS == 'W') {
      ret = -(ret);
    }
    return ret;
  }
  public float getAltitude() {
    return this.altitude;
  }

  public String toXML() {
    String ret = "";
    ret+="<GPS>\n";
    ret+="\t<lat>"+lat+"</lat>\n";
    //   ret+="\t<latS>"+latS+"</latS>\n";
    ret+="\t<lon>"+lon+"</lon>\n";
    //    ret+="\t<lonS>"+lonS+"</lonS>\n";
    ret+="\t<timestamp>"+timestamp+"</timestamp>\n";
    ret+="</GPS>\n";
    return ret;
  }

  public String toKML() {
    String ret = "";
    ret+="\t<Placemark>\n";
    ret+="\t\t<name>"+timestamp+"</name>\n";
    if (!IMU.isEmpty()) {
      ret+="\t\t<ExtendedData>\n";
      for (Data i : IMU) {
        ret+=i.toKML();
      }
      ret+="\t\t</ExtendedData>\n";
    }
    ret+="\t\t<Point>\n";
    ret+="\t\t\t<coordinates>"+this.getDDLon()+","+this.getDDLat()+","+this.getAltitude()+"</coordinates>\n";
    ret+="\t\t</Point>\n";
    ret+="\t</Placemark>\n";
    return ret;
  }
}

IMUData.pde

Processing
public class IMUData implements Data{
  private  float roll;
  private float pitch;
  private float yaw;
  
  public IMUData(float roll, float pitch, float yaw) {
    this.roll = roll;
    this.pitch = pitch;
    this.yaw = yaw;
  }
  public float getRoll() {
    return this.roll;
  }
  public float getPitch() {
    return this.pitch;
  }
  public float getYaw() {
    return this.yaw;
  }
  public String toXML() {
    String ret = "";
    ret+="<IMU>\n";
    ret+="\t<roll>"+roll+"</roll>\n";
    ret+="\t<pitch>"+pitch+"</pitch>\n";
    ret+="\t<yaw>"+yaw+"</yaw>\n";
    ret+="</IMU>\n";
    return ret;
  }

  public String toKML() {
    String ret = "";
    ret+="\t\t\t<Data name=\"Roll\">\n";
    ret+="\t\t\t\t<value>"+this.roll+"</value>\n";
    ret+="\t\t\t</Data>\n";
    ret+="\t\t\t<Data name=\"Pitch\">\n";
    ret+="\t\t\t\t<value>"+this.pitch+"</value>\n";
    ret+="\t\t\t</Data>\n";
    ret+="\t\t\t<Data name=\"Yaw\">\n";
    ret+="\t\t\t\t<value>"+this.yaw+"</value>\n";
    ret+="\t\t\t</Data>\n";
    return ret;
  }
}

Utils.pde

Processing
public static class Utils {
  public static String NMEAtoDMm(float data) {
    String ret = "";
    int deg = (int)data/100;
    ret+=deg;
    ret+=" ";
    ret+=String.format("%.8f", data-(deg*100));
    ret+="' ";
    return ret;
  }
  
  public static float NMEAtoDD(float data){
    String ret = "";
    float deg = (int)data/100;
    //println(deg);
    deg+=((data-(deg*100))/60);
    ret+=String.format("%.8f",deg);
    ret.replace(',','.');
   // println(data +" " +deg);
    return deg;
    
  }
}

AndroidManifest.xml

XML
<?xml version="1.0" encoding="UTF-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="">
  <uses-sdk android:minSdkVersion="15" android:targetSdkVersion="24"/>
  <application android:debuggable="true" android:icon="@drawable/icon" android:label="">
    <activity android:name=".MainActivity" android:theme="@android:style/Theme.NoTitleBar">
      <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
      </intent-filter>
    </activity>
    <service android:name="blepdroid.BluetoothLeService"/>
  </application>
  <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
  <uses-permission android:name="android.permission.BLUETOOTH"/>
  <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
  <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
  <uses-permission android:name="android.permission.WAKE_LOCK"/>
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
</manifest>

sketch.properties

Processing
mode=Android
mode.id=processing.mode.android.AndroidMode

Credits

Massimiliano

Massimiliano

29 projects • 115 followers
I'm an engineer and I like robotics, embedded systems and linux. I spent a lot of time in automation and firmware development.
Michele Valentini

Michele Valentini

20 projects • 69 followers
From Pepper growing to CNC milling, i don't like to waste time sleeping

Comments