I’m going to have to re-wire the IOIO and the 1A Dual TB6612FNG motor driver board thanks to a component fault caused by some faulty wiring.
Here is a wiring diagram of the IOIO wired to 2 DC motors through the motor driver board.
I’m going to have to re-wire the IOIO and the 1A Dual TB6612FNG motor driver board thanks to a component fault caused by some faulty wiring.
Here is a wiring diagram of the IOIO wired to 2 DC motors through the motor driver board.
Printed out an enclosure for Bug’s circuit boards.
Also connected the 2 IR sensors on the bumper to the IOIO board for environment sensing. I’ve got the phone’s display to change colour based on whether or not something is detected in front of either of the two sensors.
Here’s the video:
However, the motors have stopped turning. I mistakenly connected the positive terminals from the sensors to Vin on the board instead of the 3.3V terminal and that seems to have damaged something. Oh well! I’ve just ordered a replacement IOIO board and a motor driver board.
The bumper was designed in Google Sketchup (see my previous post on this topic).
Google Sketchup saves files in .skp format. So the .skp file needed to be converted into .stl format using this su2stl plugin.
The .stl file was then imported using the MakerWare software that you can download from here.
MakerWare outputs a file (in .x3g format) that was transferred into the SD card of the printer. This file slices the model into layers that the printer uses to build the final 3D object.
A video of the build process:
And finally, the bumper on Bug, with two IR sensors for obstacle avoidance:
This is my new bumper design for Bug. Designed in Google sketchup, it includes two IR sensors (2x Sharp GP2Y0A21YK) and two flex sensors.
Waiting on my 3D printer, the Makerbot Replicator 2, which, hopefully will arrive soon so I can print this part out!
The Sharp GP2Y0A21YK is an infrared (IR) proximity sensor available from Little Bird Electronics for about $15 and this was the 2nd sensor I attempted in getting the Android robot (shall we christen him Bug?) to avoid obstacles.
The sensor outputs an analog signal between 0.4V and 3.1V to indicate distances to obstacles from 80 cm away to 10 cm away.
Watch a video of Bug avoiding obstacles using a single IR sensor by clicking on the pic above.
The first sensor I used was an ultrasonic sensor, the Parallax Ping available for $35. This sensor has a much longer range (2cm – 3m). It has a digital input and the input (trigger) signal is followed by the return (pulse width indicates distance to target) output on the same pin. I was not able to get input and output signals on the same pin working with the IOIO board, and from the forums, this seems to be a problem other people have had too.
The Sharp IR sensor has 3 leads: +ve, GND and signal. Connect the +ve and GND leads from the sensor to the 3.3V and GND pins of the IOIO board. Connect the analog signal lead to pin 34 on the IOIO (peripheral input output pin).
Once you’ve connected the sensor to the IOIO, you have to write and download an app to your phone that does the sensing and obstacle avoidance.
The following is a code snippet that does this:
/** * Modified from code from the book Getting Started with IOIO (2011 Simon Monk) * and code from http://mitchtech.net/android-ioio-range-finder/ * by Jay Chakravarty 2013 * * Simple program for Obstacle Avoidance using one Infrared Sensor */ package com.ioiobook.rover; import ioio.lib.api.AnalogInput; import ioio.lib.api.DigitalOutput; import ioio.lib.api.PwmOutput; import ioio.lib.api.exception.ConnectionLostException; //import ioio.lib.util.AbstractIOIOActivity; import ioio.lib.util.BaseIOIOLooper; import ioio.lib.util.IOIOLooper; import ioio.lib.util.android.IOIOActivity; import android.graphics.Bitmap; import android.os.Bundle; import android.view.Window; import android.widget.ProgressBar; import android.widget.SeekBar; import android.widget.TextView; public class MainActivity extends IOIOActivity { private static final int AIN1_PIN = 41; private static final int AIN2_PIN = 40; private static final int PWMA_PIN = 39; private static final int PWMB_PIN = 45; private static final int BIN2_PIN = 44; private static final int BIN1_PIN = 43; private static final int STBY_PIN = 42; private static final int LED_PIN = 0; private static final int INFRARED_PIN = 34;//infrared analog input private static final int PWM_FREQ = 100; private float left_ = 0; private float right_ = 0; TextView mXTextView, mYTextView; SeekBar mXSeekBar, mYSeekBar; private float infraredOutputVolts = 0; /** * Called when the activity is first created. Here we normally initialize * our GUI. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mXTextView = (TextView) findViewById(R.id.tvX); mXSeekBar = (SeekBar) findViewById(R.id.sbX); } /** * This is the thread on which all the IOIO activity happens. It will be run * every time the application is resumed and aborted when it is paused. The * method setup() will be called right after a connection with the IOIO has * been established (which might happen several times!). Then, loop() will * be called repetitively until the IOIO gets disconnected. */ class Looper extends BaseIOIOLooper { private DigitalOutput ain1_; private DigitalOutput ain2_; private PwmOutput pwma_; private PwmOutput pwmb_; private PwmOutput led_; private DigitalOutput bin2_; private DigitalOutput bin1_; private DigitalOutput stby_; private AnalogInput mXInput; /** * Called every time a connection with IOIO has been established. * Typically used to open pins. * * @throws ConnectionLostException * When IOIO connection is lost. * * @see ioio.lib.util.AbstractIOIOActivity.IOIOThread#setup() */ @Override protected void setup() throws ConnectionLostException { try{ ain1_ = ioio_.openDigitalOutput(AIN1_PIN); ain2_ = ioio_.openDigitalOutput(AIN2_PIN); pwma_ = ioio_.openPwmOutput(PWMA_PIN, PWM_FREQ); pwmb_ = ioio_.openPwmOutput(PWMB_PIN, PWM_FREQ); //pwma_ = ioio.openPwmOutput(new DigitalOutput.Spec(PWMA_PIN, OPEN_DRAIN), PWM_FREQ); bin2_ = ioio_.openDigitalOutput(BIN2_PIN); bin1_ = ioio_.openDigitalOutput(BIN1_PIN); stby_ = ioio_.openDigitalOutput(STBY_PIN); stby_.write(true); // On led_ = ioio_.openPwmOutput(LED_PIN,PWM_FREQ); mXInput = ioio_.openAnalogInput(INFRARED_PIN); } catch (ConnectionLostException e) { throw e; } } /** * Called repetitively while the IOIO is connected. * * @throws ConnectionLostException * When IOIO connection is lost. * @throws InterruptedException * * @see ioio.lib.util.AbstractIOIOActivity.IOIOThread#loop() */ public void loop() throws ConnectionLostException { led_.setDutyCycle((float)0.9); if( infraredOutputVolts*100 > 40 ) { //Obstacle very close, turn tracks in opposite directions (turns left on the spot) pwma_.setDutyCycle((float)0.8); ain1_.write(true); ain2_.write(false); pwmb_.setDutyCycle((float)0.8); bin1_.write(false); bin2_.write(true); } else if( infraredOutputVolts*100 > 25 ) { //Obstacle a little further away, still turn pwma_.setDutyCycle((float)0.0); ain1_.write(false); ain2_.write(true); pwmb_.setDutyCycle((float)0.8); bin1_.write(false); bin2_.write(true); } else { //No obstacles in immediate vicinity, move straight pwma_.setDutyCycle((float)0.8); ain1_.write(false); ain2_.write(true); pwmb_.setDutyCycle((float)0.8); bin1_.write(false); bin2_.write(true); } try { infraredOutputVolts = mXInput.read(); setSeekBars((int) (infraredOutputVolts * 100)); setText(Float.toString((infraredOutputVolts * 100))); Thread.sleep(10); } catch (InterruptedException e) { } } } /** * A method to create our IOIO thread. * * @see ioio.lib.util.AbstractIOIOActivity#createIOIOThread() */ @Override protected IOIOLooper createIOIOLooper() { return new Looper(); } private void setSeekBars(final int xValue) { runOnUiThread(new Runnable() { @Override public void run() { mXSeekBar.setProgress(xValue); } }); } private void setText(final String xText) { runOnUiThread(new Runnable() { @Override public void run() { mXTextView.setText(xText); } }); } }
The IOIO has the capability to output Pulse Width Modulated (PWM) signals on its pins. You can vary the duty cycle of PWM signals to control the speed of DC motors. It’s recommended that you don’t connect the IOIO directly to motors, but use a motor driver breakout board in between.
The board I’m using to power the DC motors on my Android robot is the TB6612FNG.
And this is the circuit diagram for connecting the IOIO to the TB6612FNG, modified from the book Getting Started With IOIO, by Simon Monk.
IOIO to TB6612FNG motor driver board circuit diagram, modified from the book Getting Started with IOIO (2011 Simon Monk)
The only modifications I’ve made to Simon’s original circuit diagram are:
1. I’m using a 9V power supply instead of his 6V.
2. Consequently, I’ve connected Vm, the motor’s power supply to the 5V
output on the IOIO board instead of directly to the batteries as the
motors I’m using are 6V DC motors.
So, the following are the steps to do this:
1. Solder a header onto the side of the TB6612FNG board with pins Vm to GND.
2. Solder 7 pins onto IOIO board from outputs 39 to 45. Do this so that the pins stick out off the top of the IOIO board and the TB6612FNG can later be threaded onto these pins.
3. Solder the TB6612FNG to the IOIO using the pins from step 2, so that the outputs 39 to 45 on the IOIO are connected to inputs PWMA to GND on the TB6612FNG.
4. Finally, wire all connections as shown in the circuit diagram shown earlier.
Note that I’ve not soldered on a switch as yet in the image above.
Also, the PowerTech power supply I was using in my previous post turned out to be woefully inadequate in powering the motors as it was pumping out a mere 500 mA. So I used a 9V alkaline battery instead.
Watch the video of the robot motors being driven from the phone here:
If your motors turn in the wrong direction, just reverse the motor output polarities on the pins A1/A2 and B1/B2 of the TB6612FNG.
And here’s the Java code to run the motors from an Android app.
/** * Modified from code from the book Getting Started with IOIO (2011 Simon Monk) * by Jay Chakravarty 2012 * * Simple program to connect to two motors and drive them forward * using Pulse Width Modulation (PWM) */ package com.ioiobook.rover; import ioio.lib.api.DigitalOutput; import ioio.lib.api.PwmOutput; import ioio.lib.api.exception.ConnectionLostException; //import ioio.lib.util.AbstractIOIOActivity; import ioio.lib.util.BaseIOIOLooper; import ioio.lib.util.IOIOLooper; import ioio.lib.util.android.IOIOActivity; import android.os.Bundle; public class MainActivity extends IOIOActivity { private static final int AIN1_PIN = 41; private static final int AIN2_PIN = 40; private static final int PWMA_PIN = 39; private static final int PWMB_PIN = 45; private static final int BIN2_PIN = 44; private static final int BIN1_PIN = 43; private static final int STBY_PIN = 42; private static final int LED_PIN = 0; private static final int PWM_FREQ = 100; private float left_ = 0; private float right_ = 0; //private RoverControlView roverControlView_; /** * Called when the activity is first created. Here we normally initialize * our GUI. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //roverControlView_ = new RoverControlView(this); //roverControlView_.setBackgroundColor(Color.WHITE); //setContentView(roverControlView_); } /** * This is the thread on which all the IOIO activity happens. It will be run * every time the application is resumed and aborted when it is paused. The * method setup() will be called right after a connection with the IOIO has * been established (which might happen several times!). Then, loop() will * be called repetitively until the IOIO gets disconnected. */ class Looper extends BaseIOIOLooper { private DigitalOutput ain1_; private DigitalOutput ain2_; private PwmOutput pwma_; private PwmOutput pwmb_; private PwmOutput led_; private DigitalOutput bin2_; private DigitalOutput bin1_; private DigitalOutput stby_; /** * Called every time a connection with IOIO has been established. * Typically used to open pins. * * @throws ConnectionLostException * When IOIO connection is lost. * * @see ioio.lib.util.AbstractIOIOActivity.IOIOThread#setup() */ @Override protected void setup() throws ConnectionLostException { ain1_ = ioio_.openDigitalOutput(AIN1_PIN); ain2_ = ioio_.openDigitalOutput(AIN2_PIN); pwma_ = ioio_.openPwmOutput(PWMA_PIN, PWM_FREQ); pwmb_ = ioio_.openPwmOutput(PWMB_PIN, PWM_FREQ); //pwma_ = ioio.openPwmOutput(new DigitalOutput.Spec(PWMA_PIN, OPEN_DRAIN), PWM_FREQ); bin2_ = ioio_.openDigitalOutput(BIN2_PIN); bin1_ = ioio_.openDigitalOutput(BIN1_PIN); stby_ = ioio_.openDigitalOutput(STBY_PIN); stby_.write(true); // On led_ = ioio_.openPwmOutput(LED_PIN,PWM_FREQ); } /** * Called repetitively while the IOIO is connected. * * @throws ConnectionLostException * When IOIO connection is lost. * @throws InterruptedException * * @see ioio.lib.util.AbstractIOIOActivity.IOIOThread#loop() */ public void loop() throws ConnectionLostException { led_.setDutyCycle((float)0.9); //Setting PWM Duty Cycle for 1st motor //Note: This should not exceed 1.0 //Vary between 0 and 1 to achieve different speeds pwma_.setDutyCycle((float)1.0); ain1_.write(false); ain2_.write(true); //Setting PWM Duty Cycle for 2nd motor //Note: This should not exceed 1.0 //Vary between 0 and 1 to achieve different speeds pwmb_.setDutyCycle((float)1.0); bin1_.write(false); bin2_.write(true); try { Thread.sleep(10); } catch (InterruptedException e) { } } } /** * A method to create our IOIO thread. * * @see ioio.lib.util.AbstractIOIOActivity#createIOIOThread() */ @Override protected IOIOLooper createIOIOLooper() { return new Looper(); } }
The IOIO board (unlike the Arduino) does not come with headers attached on it, so you’ve got to solder them on yourself. Use the Arduino headers (again available from Little Bird Electronics) and solder them on to the board. I’ve used an 8 pin header on the VIN side of the board and a 6 pin header for the GND side of the board, which are by the way the two pins across which you can apply 5-15V DC (with a minimum of 500 mA current). I’m using a PowerTech battery eliminator with a variable (3-12V) output voltage power supply. In my experience, these often don’t supply the correct voltage and make sure you check the voltage across the output. In this particular case, I found that the 3V output actually gives a 5.75-6V output, which is what I’m using.
Now, if you attach your phone through the USB cable to the IOIO, it should start charging from it.
If you’ve already been programming Android apps with Eclipse, as I have, you would’ve thought that the downloading and running of the HelloIOIO app would’ve been a synch. As with everything software, you would’ve been wrong. It is just impossible to get new apps involving new libs up and running without some fiddling around!
IOIO, if you don’t already know what it is, is a tiny PCB board invented by Ytai Ben-Tsvi that enables you to use your Android device (tablet/phone) to control sensors and actuators, so you can make it actually do something useful. Like using your cutting board to control the display of your Android device while looking up recipes so you don’t have to touch the screen using your messy hands!
Watch the video of the MIT Media Lab guys building this contraption here: http://player.vimeo.com/video/36862291
The board is sold in Australia by Little Bird Electronics for $55.
You can download the IOIO library and example code from here:
https://github.com/ytai/ioio/wiki/IOIO-Over-Bluetooth
Once you’ve unzipped the folder and imported all the projects into Eclipse, you will get the error “Project has no default.properties file! Edit the project properties to set one.”
This is because at some point, the Android Development Toolkit (ADT) for Eclipse had its properties files renamed from project.properties to default.properties.
So, I renamed the project.properties file to default.properties in all the imported projects (including the libraries IOIOLib, IOIOLibAccessory and the IOIOLibBT).
After this, the library projects IOIOLib, IOIOLibAccessory and IOIOLibBT compiled fine, but my HelloIOIO project still would not compile. I found that the problem was with the IOIOLibAccessory_src and the IOIOLibBT_src libraries in the HelloIOIO folder. I deleted these folders from the HelloIOIO folder as the project did not seem to be using these particular libraries and that solved the problem (for now) and the HelloIOIO project compiled successfully.
If you run the project, you should get the following image on your emulator screen.
Those of you un-familiar with the emulator need to know that you will need to give it 2-3 minutes to boot into the Android home screen and then when you unlock the screen (by swiping at the bottom), only then does the app show up.
If you now connect your phone to your computer through USB, you should get the same screen you got on your emulator on your phone.