Tag Archives: IOIO

Success!

Yesterday I tested the fully built robot and had a lot of success with minor tweaking.

TEST 1

The first test showed that my steering values were way to steep. So I decreased them, and increase the drive speed; allowing the robot to steer more smoothly towards its destination. Along with the steering issues I found that a Bluetooth connection was a little to slow for driving a robot efficiently.

Bluetooth Testing

This test clearly show the latency between drive command, and robot action

 Test 2

This test showed the the drive / steering values are working smoothly. However This test showed a hint a a bug that was hidden in my code. At this point I formed a hypothesis.

How the robot determines if it is at the target destination is by examining the robots gps accuracy (using it to create a radius. around its location) and the destination’s radius (5 meters in these tests).

If the robots accuracy circle enters the destinations circle by 5 meters, then the robot is assumed to be in the destination’s radius.

For these tests, the robot was programmed to stop it’s autonomous routine if the robot senses that it is at it’s target destination.

TEST 3

During this test I watched the screen more closely as the robot was preforming it’s task, confirmed my hypothesis about the GPS accuracy bug.

After this test I decided to add a simple counter to avoid false positives. This counter will count the number of times (in a row) that the robot’s location is reported to be at the destination. If this counter reaches 5, then the robot will stop.

TEST 5

This test shows that the counter mentioned above fixed my GPS problems. It also showed that it might be a good idea for me to start implementing some sensors to prevent the robot from crashing into things.

TEST 7

This test is a perfect success with out user interaction.

The robot source code is here

Building A New Robot

I was having a lot of problems with using my RC truck base, most of them being power issues. So I decided to use my old Vex square bot base. I was perfect because of it’s size and weight. The only problem was that I couldn’t power the Vex motors with the IOIO board. So I bought a really nice TB6612FNG Motor Driver Breakout Board for $9.

The first thing I had to do is wire the Board to the IOIO. Here is how I wired is

  • VM  : 7.2V from battery
  • VCC : 3.3V from IOIO
  • A01 : Right Motor (+)
  • A02 : Right Motot (-)
  • B01 : Left Motor (+)
  • B02 : Left Motor (-)
  • PWMA : IOIO Port 4
  • AIN2 : IOIO Port 5
  • AIN1 : IOIO Port 6
  • STBY :  IOIO Port 7
  • BIN1 :  IOIO Port 8
  • BIN2 :  IOIO Port 9
  • PWMB :  IOIO Port 10
  • ALL GND’s : Battery Ground (-)

Once that was complete, I had to modify my Vex motor modules to work with the new motor driver. This was as simple as removing the original pwm driver board out of the vex motors, and wiring them into the motor driver.

 

Using code I source from here,  I was able to integrate the Motor Driver into my application and test it.

 

 

Connecting to the IOIO via Bluetooth

According to the official documentation,the IOIO can be connected to an android device (api level 7+) via a Bluetooth dongle since Bootloader V3.0 + App V3.10. After reading this is decided to buy a Bluetooth dongle. As soon as I received it, I quickly thumbed though the documentation again and found that I only needed to add the Bluetooth permission. So I updated my IOIO Truck project, and pushed it to the android device. At this point all I had to do is pair IOIO to the android device, and start the IOIO Truck application. Once started, I discovered that it wasn’t connecting! So I started investigating…

I quickly learned that the IOIOThread can only handle one type of connection (per thread). So this means that you need 2 IOIOThreads if you wan to connect via USB and Bluetooth. After reading more of the documentation, I noticed that if I used AbstractIOIOActivty, I would not of had a problem. AbstractIOIOActivity maintains a collection of threads that maintain the different connections.

Since my application uses the android compatibility library and map views, I could not simply extend AbstractIOIOActivity. So I decided to Create my own IOIOManager class based off of AbstractIOIOActivity and slightly modify my existing IOIOThread class.

/**
 * IOIOManager.java
 * @date Jan 21, 2012
 * @author ricky barrette
 * @author Twenty Codes, LLC
 * 
 * Copyright 2012 Richard Barrette
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *		http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.TwentyCodes.android.ioio;

import ioio.lib.bluetooth.BluetoothIOIOConnectionDiscovery;
import ioio.lib.util.IOIOConnectionDiscovery;
import ioio.lib.util.SocketIOIOConnectionDiscovery;
import ioio.lib.util.IOIOConnectionDiscovery.IOIOConnectionSpec;

import java.util.Collection;
import java.util.LinkedList;

import android.util.Log;

/**
 * This class manages the IOIO connectivity threads. It is based on the AbstractIOIOActivity
 * Remember that onConnected(), loop(), and onDisconnected() are called from the one of the IOIO threads
 * @author ricky barrette
 */
public abstract class IOIOManager implements IOIOListener{

	private static final String TAG = "IOIOManager";
	private Collection mThreads = new LinkedList();

	/**
	 * Aborts the IOIO connectivity threads and joins them
	 * @throws InterruptedException
	 * @author ricky barrette
	 */
	public void abort() throws InterruptedException {
		for (IOIOThread thread : mThreads)
			thread.abort();
		joinAllThreads();
	}

	/**
	 * Joins all the threads
	 * @throws InterruptedException
	 * @author ricky barrette
	 */
	private void joinAllThreads() throws InterruptedException {
		for (IOIOThread thread : mThreads)
			thread.join();
	}

	/**
	 * Creates all the required IOIO connectivity threads
	 * @author ricky barrette
	 */
	private void createAllThreads() {
		mThreads.clear();
		Collection specs = getConnectionSpecs();
		for (IOIOConnectionSpec spec : specs)
			mThreads.add(new IOIOThread(spec.className, spec.args, this));
	}

	/**
	 * Starts IOIO connectivity threads
	 * @author ricky barrette
	 */
	public void start() {
		createAllThreads();
		for (IOIOThread thread : mThreads)
			thread.start();
	}

	/**
	 * @return
	 * @author Ytai Ben-Tsvi
	 */
	private Collection getConnectionSpecs() {
		Collection result = new LinkedList();
		addConnectionSpecs(SocketIOIOConnectionDiscovery.class.getName(),result);
		addConnectionSpecs(BluetoothIOIOConnectionDiscovery.class.getName(), result);
		return result;
	}

	/**
	 * @param discoveryClassName
	 * @param result
	 * @author Ytai Ben-Tsvi
	 */
	private void addConnectionSpecs(String discoveryClassName, Collection result) {
		try {
			Class< ?> cls = Class.forName(discoveryClassName);
			IOIOConnectionDiscovery discovery = (IOIOConnectionDiscovery) cls.newInstance();
			discovery.getSpecs(result);
		} catch (ClassNotFoundException e) {
			Log.d(TAG, "Discovery class not found: " + discoveryClassName+ ". Not adding.");
		} catch (Exception e) {
			Log.w(TAG,"Exception caught while discovering connections - not adding connections of class "+ discoveryClassName, e);
		}
	}
	
	/**
	 * @param isStatLedEnabled the isStatLedEnabled to set
	 * @author ricky barrette
	 */
	public void setStatLedEnabled(boolean isStatLedEnabled) {
		for(IOIOThread thread : mThreads)
			thread.setStatLedEnabled(isStatLedEnabled);
	}

	/**
	 * Sets the update interval of the IOIO thread
	 * @param ms
	 * @author ricky barrette
	 */
	public void setUpdateInverval(long ms){
		for(IOIOThread thread : mThreads)
			thread.setUpdateInverval(ms);
	}

}

Using the IOIOManager is simple, You just need to create an object that extends it, then you can manage it just like you would a single IOIO Thread.

Here is an example clip from my Test Activity

/**
 * Called when the application is paused. We want to disconnect with the
 * IOIO at this point, as the user is no longer interacting with our
 * application.
 */
@Override
protected void onPause() {
	try {
		mIOIOManager.abort();
	} catch (InterruptedException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	super.onPause();
}

/**
 * Called when the application is being resumed
 * We want to create a new IOIOManager and start it
 */
@Override
protected void onResume() {
	super.onResume();
	mIOIOManager = new IOIOTruckManager();
	mIOIOManager.start();
}

Here is a quick video demonstrating my test

All code is available here

Planning for a self navigating robot

As I mentioned in the previous post, I plan on building an autonomous navigation robot that is powered by an android device coupled with the IOIO board. The basic idea is to create an application that I can selected a point on the map and hit “Go”. This build will be the most advanced robot build I have ever attempted, and I’m quite excited about it. My only other previous robot experience is with my old VEX robotics kit, building autonomous robots that are only capable of blindly feeling their away around, with no end goal, other than navigating a maze. Before I was held back by the capabilities of the VEX controller’s pic and a lack of sensors (due to my budget); now I have the processing power of an android device and access to all the sensors that it contains.

For this project I will be accessing the android devices internal GPS and compass. Using the information provided by them I plan on using the information to drive a r/c truck or robot base to a specific latitude, longitude autonomously. Keeping this information in mind I planned out the navigation activity.

 

The Navigation Activity:

  • Must have a map view to display the robot’s current location and direction.
  • Must have gps accuracy information displayed
  • Must allow the user to select a point on the map (draw a point with a circle around it)
  • Must have a “Go” button
  • Must display onscreen log information to assist in debugging

 

Once the UI was done, then I started planning out the algorithms needed to drive and steer the robot to it’s destination. The first thing that needs to be done is to process the robot’s location & heading and the destination’s location and bearing. With this information we can learn the answers to the following questions:

  1. Is the robot at it’s target location?
  2. What is the distance from the robot to it’s destination?
  3. Is the robot facing the target location?
  4. If not, what is the bearing to the destination?
Knowing this information we can plan out a few simple methods in pseudo code.

 

public void updateDrive(){
    if the is robot with in 10 meters of it’s destination {
        stop robot and cancel the autonomous routine
    } else {
        drive the robot forward
    }
}

 

public void updateSteering(){
     if the robot is heading towards the the destination {
        steer stright
    } else {
        if the robot is heading left of the destination {
            steer the robot right;
        }
        if the robot is heading right of the destination {
            steer the robot left;
        }
    }
}

Using the pseudo code above, I will be creating very simple navigation algorithms to drive and steer the robot to it’s selected location.

The IOIO Board

Recently I purchased a IOIO board so I can start playing around with android’s ability to interact with USB peripheral devices. Ever since I bought my first android device, I always wanted to tap into the power that these devices offer, so as soon as it arrived I started playing with it.

My first task was to solder all the female headers, and the power connector. Once I was done with that I quickly fired up Eclipse and compiled the example code Hello IOIO Power. The code was easy to understand so I decided that i would quickly modify it by adding a seek bar to the main UI, and mapping it to control a port on the board.

My Second task was to learn how to control a rc hobby servo. After some research, I learned is that servos require 4-6 volts DC are controlled  via Pulse Width Modulation (PWM). You will need set the PWM frequency for analog 30-50hz, and for digital servos, 300-400hz. Once you know this information all you need to do is adjust the pulse width of the PWM signal that is controlling the servo. The pulse width is required to be between 1-2 milliseconds. After learning this, I quickly google’d for the color code of one of my old vex servos and learned that the white was the signal, orange was Vin, and black was ground.

I Then finished updating the code, and wired up the IOIO for my first servo control test.

Taking what I learned from the example I Created a simple IOIOThread base class that was based of the thread from Hello IOIO Power. When ever I want to make a new program for the IOIO, I simply have to extend this class.


/**
 * IOIOThread.java
 * @date Jan 11, 2012
 * @author ricky barrette
 * @author Ytai Ben-Tsvi
 * @author Twenty Codes, LLC
 */
package com.TwentyCodes.android.IOIOTruck.ioio;

import ioio.lib.api.DigitalOutput;
import ioio.lib.api.IOIO;
import ioio.lib.api.IOIOFactory;
import ioio.lib.api.exception.ConnectionLostException;

/**
 * This is the thread that maintains the IOIO interaction.
 * 
 * It first creates a IOIO instance and wait for a connection to be
 * established.
 * 
 * Whenever a connection drops, it tries to reconnect, unless this is a
 * result of abort().
 * 
 * @author Ytai Ben-Tsvi
 * @author ricky barrette
 */
public abstract class IOIOThread extends Thread{

	private IOIO mIOIO;
	private boolean isAborted = false;
	private long mUpdateInterval = 10;
	private boolean isStatLedEnabled = false;

	/**
	 * Abort the connection.
	 * 
	 * This is a little tricky synchronization-wise: we need to be handle
	 * the case of abortion happening before the IOIO instance is created or
	 * during its creation.
	 */
	synchronized public void abort() {
		isAborted = true;
		if (mIOIO != null) {
			mIOIO.disconnect();
		}
	}

	/**
	 * @return the isStatLedEnabled
	 */
	public boolean isStatLedEnabled() {
		return isStatLedEnabled;
	}

	/**
	 * Called when the IOIO is connected.
	 * This is where you want to register and initialize each port
	 * @param ioio 
	 */
	public abstract void onConnected(IOIO ioio) throws ConnectionLostException;

	/**
	 * Called when the IOIO is disconnected.
	 */
	public abstract void onDisconnect();

	/**
	 * Called when the IOIO is to be updated.
	 * This is where you want to update the values for each port
	 */
	public abstract void onUpdate() throws ConnectionLostException;

	/**
	 * Thread Body
	 * (non-Javadoc)
	 * @see java.lang.Thread#run()
	 */
	@Override
	public void run() {
		while (true) {
			synchronized (this) {
				if (isAborted) {
					break;
				}
				mIOIO = IOIOFactory.create();
			}
			try {
				/*
				 * Here we will try to connect to the IOIO board.
				 * 
				 * the waitForConnect() is blocking until it can connect
				 */
				mIOIO.waitForConnect();

				/*
				 * Here we register and initialize each port 
				 */
				DigitalOutput statLed = mIOIO.openDigitalOutput(IOIOValues.STAT_LED_PORT, true);
				onConnected(mIOIO);

				/*
				 * Here we will update the ports every 10 ms (default)
				 */
				while (true) {
					onUpdate();
					statLed.write(!isStatLedEnabled);
					sleep(mUpdateInterval );
				}
			} catch (ConnectionLostException e) {
				onDisconnect();
			} catch (Exception e) {
				e.printStackTrace();
				mIOIO.disconnect();
				onDisconnect();
				break;
			} finally {
				try {
					mIOIO.waitForDisconnect();
					onDisconnect();
				} catch (InterruptedException e) {
				}
			}
		}
	}

	/**
	 * Sets the stat led on / off
	 * @param isStatLedEnabled the isStatLedEnabled to set
	 */
	public synchronized void setStatLedEnabled(boolean isStatLedEnabled) {
		this.isStatLedEnabled = isStatLedEnabled;
	}

	/**
	 * Sets the update interval of the IOIO thread
	 * @param ms
	 */
	public synchronized void setUpdateInverval(long ms){
		mUpdateInterval = ms;
	}

}

 

There is more to come, since I have also decided that the best way to put my knowledge to the test is to build an autonomous vehicle/robot that can navigate to a selected point on the map, using the phone’s GPS and compass.