Sunday, July 13, 2014

Socket Server to transfer Accelerometer Sensor data to PC

Hi Guys,

Recently, I have been trying to get the accelerometer data on PC in real time. Here is how to make it work.

The idea basically is to create a socket server in the Android device and a socket client in local PC to transfer data over wifi. Now lets create a socket server in the Android device which transmits the linear acceleration data.

Create an android Project in Eclipse:
package com.example.myserver;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import android.app.Activity;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.TextView;

public class MainActivity extends Activity implements SensorEventListener {
    String mClientMsg = "";
    Thread myCommsThread = null;
    public static final String TAG = "SocketServer";
    private CommsThread commsThread = null;
    TextView tv;
    PrintWriter out;
    private float ax, ay, az;
    private long timenow = 0, timeprev = 0, timestamp =0 ;

    private SensorManager sm;
    private Sensor sensor;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv = (TextView) findViewById(R.id.textView1);
        sm = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        sensor = sm.getSensorList(Sensor.TYPE_LINEAR_ACCELERATION).get(0);
    }

    @Override
    protected void onResume() {
        // TODO Auto-generated method stub
        super.onResume();
        sm.registerListener(this, sensor, SensorManager.SENSOR_DELAY_UI);
        this.commsThread = new CommsThread();
        this.myCommsThread = new Thread(this.commsThread);
        this.myCommsThread.start();
    }

    @Override
    protected void onPause() {
        // TODO Auto-generated method stub
        super.onPause();
        sm.unregisterListener(this);
        if (commsThread != null) {
            commsThread.stopComms();
        }
    }    

    Handler myHandler = new Handler(){
        public void handleMessage(Message msg){
            TextView status = (TextView) findViewById(R.id.textView3);
            status.setText("Status: Streaming Now!");
        }
    };

    class CommsThread implements Runnable {
        private volatile boolean stopFlag = false;
        private ServerSocket ss = null;
        private static final int SERVERPORT = 6000;
        public void run() {
            Socket s = null;
            try {
                ss = new ServerSocket(SERVERPORT);
            } catch (IOException e) {
                e.printStackTrace();
            }
            
            try {
                s = ss.accept();
            } catch (IOException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
            myHandler.sendEmptyMessage(0);
            
            while(!stopFlag){
                try {
                    out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(s.getOutputStream())), true);
                    out.printf("*#%3.2f#%3.2f#%3.2f#%2d#*\n",ax,ay,az,(int)timestamp );
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }

        public void stopComms() {
            // TODO Auto-generated method stub
            this.stopFlag = true;
            if(ss != null){
                try {
                    ss.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }         
        }
    }

    @Override
    public void onAccuracyChanged(Sensor arg0, int arg1) {
        // TODO Auto-generated method stub       
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        // TODO Auto-generated method stub
        ax = event.values[0];
        ay = event.values[1];
        az = event.values[2];
        timenow = event.timestamp;
        timestamp = (timenow - timeprev)/1000000;
        refreshDisplay();
    }

    private void refreshDisplay() {
        // TODO Auto-generated method stub
        String output = String.format("time: %d -- x:%03.2f | Y:%03.2f | Z:%03.2f", timestamp, ax,ay,az);
        timeprev = timenow;
        tv.setText(output);
    }
}


In the AndroidManifest.xml add the following lines:
    <uses-permission android:maxSdkVersion="19" android:name="android.permission.INTERNET"/>
    <uses-permission android:maxSdkVersion="19" android:name="android.permission.ACCESS_NETWORK_STATE"/>

Now install the socket server on the Android device and launch the program. The server is up and running. It now waits for the client to connect and then transmit the real-time linear acceleration data to the client.

Now lets write a simple client to read the data on Ubuntu PC.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h> 

void error(const char *msg)
{
    perror(msg);
    exit(0);
}

int main(int argc, char *argv[])
{
    int sockfd, portno, n;
    struct sockaddr_in serv_addr;
    struct hostent *server;

    char buffer[256] = "\0";
    if (argc < 3) {
       fprintf(stderr,"usage %s hostname port\n", argv[0]);
       exit(0);
    }

    portno = atoi(argv[2]);
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) 
        error("ERROR opening socket");
    server = gethostbyname(argv[1]);

    if (server == NULL) {
        fprintf(stderr,"ERROR, no such host\n");
        exit(0);
    }

    bzero((char *) &serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    bcopy((char *)server->h_addr, 
         (char *)&serv_addr.sin_addr.s_addr,
         server->h_length);
    serv_addr.sin_port = htons(portno);
    if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) 
        error("ERROR connecting");

    //printf("Please enter the message: ");
    bzero(buffer,256);

    //fgets(buffer,255,stdin);
    n = write(sockfd,buffer,strlen(buffer));
    if (n < 0) 
         error("ERROR writing to socket");
    while(1){
        bzero(buffer,256);
        n = read(sockfd,buffer,255);
        if (n < 0) 
            error("ERROR reading from socket");
        printf("%s\n",buffer);
    }
    close(sockfd);
    return 0;
}



compile the above code using
gcc -o socketclient client.c
To connect to the server over wifi network:
./socketclient 192.168.1.2 6000
to connect to the server via USB cable:
adb forward tcp:1234 tcp:6000
./socketclient localhost 1234
Now the data will be streaming on the Ubuntu PC. I'll try to plot this data in my next blog.

References:
C socket programming:
1. http://www.linuxhowtos.org/C_C++/socket.htm 
USB port forwarding:
2. http://www.anothem.net/archives/2010/02/15/communicating-over-the-usb-cable/
Android Socket Programming:
3. http://thinkandroid.wordpress.com/2010/03/27/incorporating-socket-programming-into-your-applications/
4. http://www.edumobile.org/android/android-development/socket-programming/ 

1 comment:

  1. How can I stream data to blender to control objects like camera or cube? Is there any script available with you?

    ReplyDelete