Electronic Anti-roll system for tractor (or how to connect IOIO to a Basic Atom


“Tractor”, what tractor… ? That’s what you must be wondering right now, as I don’t often blog about tractors… especially full scale agricultural ones…

This is a slightly different post for me, in that it’s about some help I gave to 2 guys in Germany, working on a hydraulic anti-roll system for a tractor.
Wow… I never though I would be working on “revolutionising the agriculture” as they’ve put it… 🙂

Basic Atom Pro M40 - IOIO - and the ICONIA A500 Android tablet

It sounds awesome, but my actual contribution is very limited.

The Basic Atom Pro M40 is connected to an inclination sensor and does some funky stuff for the anti-rolling system, but the guys wanted to have some data nicely displayed on an Android tablet.

And that’s where they needed my help…

They initially wanted to use I2C to connect the IOIO to the Basic Atom, which I thought was fine, until I realised that the IOIO can NOT be a I2C slave… I therefore convinced them it would be easier to go down the UART route and after throwing together a simple program, we seem to be in business !

There’s really not much else to say, the program is really trivial, but it’s a nice basic example on how to use a USART on the IOIO board !

Without further due, here’s the main and only class  I2CAtomProTractorActivity :

package com.trandi.i2catompro;

import ioio.lib.api.DigitalOutput;
import ioio.lib.api.Uart;
import ioio.lib.api.exception.ConnectionLostException;
import ioio.lib.util.AbstractIOIOActivity;

import java.io.InputStream;
import java.lang.Thread.UncaughtExceptionHandler;

import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;

public class I2CAtomProTractorActivity extends AbstractIOIOActivity {
	private static final String LOG_TAG = "APT";
	private static final int RX_PIN = 4;
	private static final int TX_PIN = 5;
	private static final int UART_SPEED = 9600;

	private MyIOIOThread _IOIOthread;

	private TextView _varField;
	private TextView _msg;

	/**
	 * Called when the activity is first created. Here we normally initialise our GUI.
	 */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {
			@Override
			public void uncaughtException(Thread thread, Throwable ex) {
				Log.e(LOG_TAG, "", ex);
			}
		});

		setContentView(R.layout.main);
		_varField = (TextView) findViewById(R.id.textViewVarVal);
		_msg = (TextView) findViewById(R.id.textViewMsg);
	}

	/**
	 * 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 MyIOIOThread extends AbstractIOIOActivity.IOIOThread {
		private DigitalOutput _onboardLED; // The on-board LED
		private Uart _uart;
		private InputStream _atomDataIS;
		private final byte[] _data = new byte[2];

		/**
		 * Called every time a connection with IOIO has been established.
		 * Typically used to open pins.
		 *
		 * @throws ConnectionLostException When IOIO connection is lost.
		 */
		@Override
		protected void setup() throws ConnectionLostException {
			msg("IOIO Connected !", null);

			try {
				_onboardLED  = ioio_.openDigitalOutput(0, true);

				// initialize the UART
				if(_uart != null) _uart.close();
				_uart = ioio_.openUart(RX_PIN, TX_PIN, UART_SPEED, Uart.Parity.NONE, Uart.StopBits.ONE);
				_atomDataIS = _uart.getInputStream();
				msg("Connected to UART", null);
			} catch (Throwable e) {
				msg("Can't connect to the UART (" + RX_PIN + ", " + TX_PIN + ", " + UART_SPEED + ")", e);
			}
		}

		/**
		 * Called repetitively while the IOIO is connected.
		 *
		 * @throws ConnectionLostException When IOIO connection is lost.
		 */
		@Override
		protected void loop() throws ConnectionLostException {
			try {
				if(_atomDataIS.available() > 0) {
					onboardLED(true);
					if(_atomDataIS.read() == '#'){
						// this is a message for us, expect 2 more bytes
						_atomDataIS.read(_data, 0, _data.length);
						msg("Bytes[" + _data[0] + ", " + _data[1] + "]", null);

						// transform the 2 bytes into an integer
						final int number = _data[0] + _data[1] << 8;

						// refresh the display (HAS to be on the UI Thread !)
						runOnUiThread(new Runnable() {
							@Override
							public void run() {
								_varField.setText(String.valueOf(number));
							}
						});
					}

					onboardLED(false);
				}

				// don't overheat the CPU
				Thread.sleep(10);
			} catch (Exception e) {
				msg("Can't read serial data", e);
			}
		}

		private void onboardLED(boolean on) throws ConnectionLostException{
			_onboardLED.write(!on);
		}

	} // end IOIOThread

	private void msg(final String msg, final Throwable e){
		runOnUiThread(new Runnable() {
			@Override
			public void run() {
				_msg.setText(msg + (e != null ? " - " + e.getMessage() : ""));
			}
		});
	}

	/**
	 * A method to create our IOIO thread.
	 */
	@Override
	protected AbstractIOIOActivity.IOIOThread createIOIOThread() {
		_IOIOthread = new MyIOIOThread();
		return _IOIOthread;
	}

The layout/main.xml :

<!--?<span class="hiddenSpellError" pre=""-->xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

<TextView android:text="Inclination: " android:id="@+id/textViewVar" android:layout_width="wrap_content" android:layout_height="wrap_content">
id="@+id/textViewVarVal" android:textAppearance="?android:attr/textAppearanceLarge" android:layout_width="wrap_content" android:layout_height="wrap_content">
<TextView  android:text="Message" android:id="@+id/textViewMsg"  android:layout_height="wrap_content" android:layout_width="wrap_content"></TextView>

</LinearLayout>

And finally the AndroidManifest.xml file :

<?xml version="1.0" encoding="utf-8"?>
xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.trandi.i2catompro"
      android:versionCode="1"
      android:versionName="0.1">
    <uses-sdk android:minSdkVersion="3" />
    <uses-permission android:name="android.permission.INTERNET"></uses-permission>

    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".I2CAtomProTractorActivity"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

    </application>
</manifest>

4 Responses to Electronic Anti-roll system for tractor (or how to connect IOIO to a Basic Atom

  1. student says:

    could you please post some example code where ioio is used as a twi master… I’m working on a project and i can’t make out where is the mistake… The circuitry is fine… there has to be a problem with the code but where i don’t know. Probably i’m missing on something basic. An example code would be a great help

  2. Jean-Francois Messier says:

    Bonjour !!!

    It’s really interesting.
    I am a farmer, and I am interested in IOIO board myself
    Maleureusement, I miss the basics for programming and electronics
    but I have plenty of ideas for implementation.

    But I am perceverance, and attentive to the development of projects for IOIO about Drones and vehicles. J, I bought my board … IOIO

    I would love to know if it’s an Open Source and Open Hardware. Give me more information please.

    Question: why use an external module, the gyroscope’s Android for it to work?

    Thank you for sharing your experience on programing IOIO me this confirms that it is possible to DIY an autopilot for my tractor.

    Jean-Francois
    messier (dot) jeans (d_t) francois (_t) gmail (do_) com
    Canada

    PS I just discovered your blog, I’ll have a lot of reading to do. 😉
    I will be able work on my English. Merci

    • trandi says:

      Bonjour Jean-Francois,

      Ca fait plaisir de voir d’autres fans francophones de la platine IOIO…
      Je vais quand meme continuer ma reponse en anglais pour que tous les autres puissent en profiter…

      From what I know it is indeed Open Source and Hardware, and you can check this and all the details here:
      https://github.com/ytai/ioio/wiki

      I’m not sure I understand your question regarding the gyroscopes… Yes, of course you can use the ones on your Android device, IF it has them.
      For example my phone only has an accelerometer, so I had to connect a Wii Motion Plus (which is a really nice and cheap way of adding gyros to a project !) to it: https://trandi.wordpress.com/2011/08/07/android-ioio-wii-motion-plus-gyros/

      The great thing with the IOIO board is really its simplicity of use and the fact that you can add any electronics to your Android device, without having to write a single line of low level C code…
      You also have a really great community and forum.
      Besides, the board’s creator, Ytai, is a really nice guy, quite knowledgeable, always ready to help and especially quite funny in his comments on my blog 🙂

      Dan

Leave a comment