//
you're reading...
Android, How-to's

Android App with image buttons and rotation control

rotation

 

A previous article explained how to control your EV3 robot from an Android app, using buttons. This Android app goes a step further and uses image buttons, and a custom rotation control.

It needs the 0.9.0 version of leJOS EV3, and a Wifi dongle.

To move the robot forward on backwards, you press the corresponding button, and release it when you want the robot to stop.  To rotate the robot, you rotate the control with your finger until the arro points in the required direction, and the robot then rotates to that direction.

The image above shows a virtual Android device being used to execute the app from Eclipse on a PC.

The app uses the RemoteRequestPilot class to control a differential drive robot. You will need to change the HOST variable to the IP address of your EV3, and the wheel diameter and track width parameters of the pilot, to match your robot.

As before, you need to make sure network permission is requested in your android manifest file.

The code for the rotation control is:

package org.lejos.android.sample.ev3androidrotate;

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;

public class RotationControl extends ImageView  {
  
  private float angle = 0f, oldTouchAngle = 0f;
  private RotationListener listener;
  
  public interface RotationListener {
    public void onAngleChanged(int angle);
  }
  
  public void setRotationListener(RotationListener l) {
    listener = l;
  }
  
  public RotationControl(Context context) {
    super(context);
    initialize();
  }
  
  public RotationControl(Context context, AttributeSet attrs) {
    super(context, attrs);
    initialize();
  }
  
  public RotationControl(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    initialize();
  }
  
  private float getTouchAngle(float x, float y) {
    float sx = x - (getWidth() / 2.0f);
    float sy = y - (getHeight() / 2.0f);
    
    float length = (float) Math.sqrt(sx*sx + sy*sy);
    float nx = sx / length;
    float ny = sy / length;
    
    return (float) ((Math.atan2(ny, nx) * (180.0/Math.PI)));
  }
  
  public void initialize() {
    setImageResource(R.drawable.rotate);
    setOnTouchListener(new OnTouchListener() {
         @Override
         public boolean onTouch(View v, MotionEvent event) {
           float x = event.getX(0);
           float y = event.getY(0);
           float newTouchAngle = getTouchAngle(x,y);
           float delta = newTouchAngle - oldTouchAngle;
           oldTouchAngle = newTouchAngle;
        
           switch(event.getAction() & MotionEvent.ACTION_MASK) {
           case MotionEvent.ACTION_DOWN:
        	 oldTouchAngle = newTouchAngle;
        	 break;
           case MotionEvent.ACTION_MOVE:
             invalidate();
             angle += delta;
             break;
           case MotionEvent.ACTION_UP:
        	 notifyListener((int) angle);
        	 break;
           }
           return true;
         }
      });
  }
  
  private void notifyListener(int e) {
    if (listener!=null) listener.onAngleChanged(e);
  }
  
  protected void onDraw(Canvas c) {
    c.rotate(angle, getWidth()/2, getHeight()/2);   
    super.onDraw(c);
  }
} 

The code for the main activity is:

package org.lejos.android.sample.ev3androidrotate;

import java.io.IOException;

import org.lejos.android.sample.ev3androidrotate.RotationControl.RotationListener;

import lejos.remote.ev3.RemoteRequestEV3;
import lejos.remote.ev3.RemoteRequestPilot;

import android.os.AsyncTask;
import android.os.Bundle;
import android.app.Activity;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.ImageButton;
import android.widget.Toast;

public class MainActivity extends Activity implements OnTouchListener,
		RotationListener {
	private static final String HOST = "192.168.0.9";
	private RemoteRequestEV3 ev3;
	private RemoteRequestPilot pilot;
	private int angle;
	private ImageButton forward, backward;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		forward = (ImageButton) findViewById(R.id.forward);
		forward.setOnTouchListener(this);

		backward = (ImageButton) findViewById(R.id.backward);
		backward.setOnTouchListener(this);

		RotationControl rotateView = (RotationControl) findViewById(R.id.rotate);
		rotateView.setRotationListener(this);

		// Connect to the EV3
		new Control().execute("connect", HOST);
	}

	@Override
	public void onAngleChanged(int angle) {
		new Control().execute("rotate", "" + angle);
	}

	@Override
	public boolean onTouch(View v, MotionEvent event) {
		int action = event.getAction();
		if (action == MotionEvent.ACTION_UP)
			new Control().execute("stop");
		else if (action == MotionEvent.ACTION_DOWN) {
			if (v == forward)
				new Control().execute("forward");
			else if (v == backward)
				new Control().execute("backward");
		}
		return false;
	}

	private class Control extends AsyncTask<String, Integer, Long> {
		protected Long doInBackground(String... cmd) {
			if (cmd[0].equals("connect")) {
				try {
					ev3 = new RemoteRequestEV3(cmd[1]);
					pilot = (RemoteRequestPilot) ev3.createPilot(3.5f, 20f,
							"A", "B");
				} catch (IOException e) {
					return 1l;
				}
			} else if (cmd[0].equals("rotate")) {
				if (ev3 == null)
					return 2l;
				int newAngle = Integer.parseInt(cmd[1]);
				pilot.rotate(angle - newAngle);
				angle = newAngle;
			} else if (cmd[0].equals("forward")) {
				if (ev3 == null)
					return 2l;
				pilot.forward();
			} else if (cmd[0].equals("backward")) {
				if (ev3 == null)
					return 2l;
				pilot.backward();
			} else if (cmd[0].equals("stop")) {
				if (ev3 == null)
					return 2l;
				pilot.stop();
			} else if (cmd[0].equals("close")) {
				if (ev3 == null)
					return 2l;
				pilot.close();
				ev3.disConnect();
			}
			return 0l;
		}

		protected void onPostExecute(Long result) {
			if (result == 1l)
				Toast.makeText(MainActivity.this, "Could not connect to EV3",
						Toast.LENGTH_LONG).show();
			else if (result == 2l)
				Toast.makeText(MainActivity.this, "Not connected",
						Toast.LENGTH_LONG).show();
		}
	}
}

The layout is:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <ImageButton
        android:id="@+id/backward"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_alignParentTop="true"
        android:layout_marginTop="21dp"
        android:layout_toLeftOf="@+id/rotate"
        android:background="@null"
        android:scaleType="fitCenter"
        android:src="@drawable/backward" />

    <ImageButton
        android:id="@+id/forward"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_alignTop="@+id/backward"
        android:layout_toRightOf="@+id/rotate"
        android:background="@null"
        android:scaleType="fitCenter"
        android:src="@drawable/forward" />

    <org.lejos.android.sample.ev3androidrotate.RotationControl
        android:id="@+id/rotate"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_alignTop="@+id/forward"
        android:layout_centerHorizontal="true" />

</RelativeLayout>

The images I am using are:

rotateplaybackward

Advertisements

Discussion

No comments yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

About leJOS News

leJOS News keeps you up-to-date with leJOS. It features latest news, explains cool features, shows advanced techniques and highlights amazing projects. Be sure to subscribe to leJOS News and never miss an article again. Best of all, subscription is free!
Follow leJOS News on WordPress.com
%d bloggers like this: