Posts tagged ‘robot’

Using Android as robot remote control

The flea market car / robot saga continues… Controlling the robot from my laptop via Bluetooth was cool
, but running after the robot with the laptop in my hands kind of diminished the James Bond – feeling of it. Therefore, I decided that my first application I would create for my brand new Android smartphone would be a remote control for the robot!

Luckily, the online developer information (available at http://developer.android.com), provides a wealth of information for getting started. What was more, I actually found a sample application there, called BluetoothChat, that almost did exactly what I wanted to do. The BluetoothChat application makes a connection to a Bluetooth device (this will be the robot) and it allows to send text to it once connected (the text will be the robot commands).

Google provides a complete development environment for developing Android applications, which can be downloaded at http://developer.android.com/sdk/index.html. Just follow the instructions over there to install the platform and create a “hello world” application. Connecting your phone over USB to the development computer allows you to debug / run the application on the phone. On my Ubuntu laptop, I have to restart the adb server as root after connecting the phone via USB:

(while in folder /android-sdk-linux_86/tools)
./adb kill-server
sudo ./adb start-server
./adb devices

Now let’s skip to the application. I wanted to change a few things to the BluetoothChat application:

  • actually get it connected to a Bluetooth device, because this wasn’t working right away.. ūüė¶
  • after connecting to the robot over Bluetooth, I wanted to automatically start my PING – PONG handshake (Android says “PING” and the robot answers with “PONG”, which indicates the connection is established¬†successfully¬†and the robot should start listening for commands)
  • Instead of typing the commands in the text field I wanted some big buttons (forward, backward, left, right, …)

Connecting the BluetoothChat example to a Bluetooth device

I first tried connecting the BluetoothChat Android application to Bluetooth on my laptop, but it didn’t work. Whatever I tried, I always got a “service discovery failed” exception on the following line of code in BluetoothChatService.java:

tmp = device.createRfcommSocketToServiceRecord(MY_UUID);

After a long time trying to solve this, I found this site, which suggested to change the line of code to this code:

Method m = device.getClass().getMethod("createRfcommSocket", new Class[] {int.class});
tmp = (BluetoothSocket) m.invoke(device, 1);

And this worked! Also, note that you have to connect at 57600 baud to the Android Bluetooth.

Do a handshake once connected

Once connected to the BlueSMIRF on the robot, the following should happen:

  • Android sends “PING\n” to robot
  • Robot receives this and sends “PONG\r\n” to Android
  • Android receives this, and knows the connection is succesfully established.
  • Now Android can send commands like “D,70,1” to set the servo to 70¬į and the drive motor to forward motion.

I changed the run() method of the ConnectedThread to do the handshake once connected: see code.

Big buttons that send commands to the robot

And now for the fun part.. I wanted to change the layout to have nine big buttons which would send the robot in a certain direction:

I used the example at this site to create the big button layout. Once a button is pressed, it will send a command over Bluetooth to the robot which will make it ride in that direction:

        mBRButton = (Button) findViewById(R.id.button_br);

        mBRButton.setOnClickListener(new OnClickListener() {

            public void onClick(View v) {

                // Send a message using content of the edit text widget

                String message = "D," + right + "," + backward + "\r\n";

                sendMessage(message);

            }

        });

And now a little movie to prove that it works!

The source code can be downloaded here.

edit: latest version of code is now available via https://github.com/kr3l/rommelrubot

 

Advertisements

September 4, 2010 at 5:18 pm 14 comments

Time for a new steering system

My last post was about putting Bluetooth in a flea market toy car in order to control it remotely from my laptop. One problem I had with the car was the amount of current it drew. Unexpectedly, it turned out to be the steering that drew most of the current. I thought the steering was done by a servo motor, but apparently they put a regular DC motor in it to turn the weels. A piece of plastic stops the turning and basically the motor stalls everytime you steer, and so draws the maximum amount of power..

To reduce the power-demands of the car I cut out the steering DC motor (and all the plastic around it) and glued in a servo.

Now to make the servo turn the weels, I used some good old Lego bricks. The flat one with the dents is glued to the thing that used to make the weels turn. Than I used a gear wheel glued to (God, I love hot-glue!) the servo, which makes the flat brick move. Because the servo sometimes turns too much (it’s a cheap one so not always that accurate), I cut most dents from the gear wheel. This assures that no damage is done if the gear wheel turns too much..

August 15, 2010 at 9:34 pm Leave a comment

Putting Bluetooth into a flea market toy car

On the flea market here in Ghent a few weeks ago, I bought myself a toy car with a wired remote control. Feeling destructive, I immediately removed the hood of the car, opened up the remote control and measured how the car could be controlled. It turns out there are four wires from the remote to the car. Two of them control the forward / backward motion by setting 5V or -5V across them. The two other wires control the left / right motion of the front wheels, again by setting 5V across them.

Next I soldered header pins to the wires of the car so I can control them through the L293D driver chip of my Dwengo board. Next I added the Bluesmirf module (as explained in a previous post) and taped everything together using Duct tape.

After some programming and some tweaking (putting the battery pack above the steering wheels so they have more grip) I got my car driving across the appartment ūüôā

edit: latest version of code is now available via https://github.com/kr3l/rommelrubot

May 29, 2010 at 8:39 pm Leave a comment

Distance scanner using servomotor and distance sensor

In my previous post we got a servomotor doing what we want, so now it is time to put it to use! We will mount a Sharp GP2YOA distance sensor on top of the servo, so we can measure the distance to obstacles at different angles. We can then mount this sensor-servo combination on a robot to give it a good overview of the environment!

cimg5413

The hot glue gun!

I read a lot about robotic projects online, and I have several books about the topic. The coolest tool present in all of those is without competition the hot glue gun :-).. A few months ago I was in a hobby store and came across one by accident so I bought one. Though it is not as spectacular as I had hoped for, it certainly is really handy to glue things together like lego and sensors. 

First I glued a Lego piece on the sensor:

hot glue gun

The hot glue gun, the servo and the lego

The image below shows how the component is glued to the sensor. Note the piece of cardboard to protect the electronics from the glue (though I don’t think it would hurt the electronics, I didn’t want to take the risk :p)

sensor lego cardboard

We will also glue a piece of Lego to the servo:

lego servo

 

Jop, it's a bit messy :)

Jop, it's a bit messy ūüôā

Now we can just plug the sensor Lego piece into the servo Lego piece, et voilà!

 

This already looks a bit like a robot..

This already looks a bit like a robot..

The code

The hard bits are already done in past projects:

So now it is just a matter of putting the two together.. I’ve put the code in a file called scanner.c. The scanStep() function will move the sensor one step (in this example 2¬į) and measure the distance. It will then send the current angle and distance value on the COM port using the format D,[angle],[distance].¬†

#include "scanner.h"
#define SCAN_RESOLUTION 2	//measure distance every 2¬į
short servoDir		= 0;	//0 = clockwise / 1=ccw
int distances[180/SCAN_RESOLUTION+1];
/**
 * Moves the servo from left to right and back (one step per call)
 **/
void moveServo() {
	static short servoAngle	= 90;
	short oldAngle = servoAngle;
	if (servoDir == 0) {			//clockwise
		servoAngle+=SCAN_RESOLUTION;
		if (servoAngle>=180) {
			servoDir = 1;
			//servoAngle = 0;	
		}
	} else if (servoDir == 1) {		//counterclockwise
		servoAngle-=SCAN_RESOLUTION;
		if (servoAngle<=0) {
			servoDir = 0;
		}
	}
	setServoAngle(servoAngle);
	//give servo some time to reach goal angle
	if (oldAngle>servoAngle) {
		Wait_Ms(20*(oldAngle-servoAngle));
	} else {
		Wait_Ms(20*(servoAngle-oldAngle));
	}
}
void scanStep() {
	int distance = 0;
	int angle = 0;
	moveServo();						//move servo 5¬į further
	angle = getServoAngle();
	distance = readLightSensor(0);		//read distance at this angle
	distances[angle/SCAN_RESOLUTION+1] = distance;
	fprintf (_H_USART, "D,%i,%i\n",angle,distances[angle/SCAN_RESOLUTION+1]);
}

Now we want to plot these values in Matlab. This is done using the following code. First we open the COM port and wait for data to arrive. We then put the data in an array B, where the position in B determines the angle the measurement was made at. We then plot these values so our plot resembles the directions the measurements where made at.

function [B] = sensorPlot2()
COMPORT             = 4;
SCAN_RESOLUTION     = 2;    %make sure this matches SCAN_RESOLUTION in embedded code!

%open com port
s2 = serial(['COM' num2str(COMPORT)],'BaudRate',19200);
fopen(s2);
s2.ReadAsyncMode = 'continuous';

%open plot window
colordef none
h=figure('Color',[0.3 0.3 0.3]);

%init values
quit=0;
paused=0;
B = zeros(180/SCAN_RESOLUTION+1,1);
theAngles = (1:length(B))*SCAN_RESOLUTION*pi/180; %we will plot values on these angles

try
    while 1
        while ~s2.BytesAvailable    %wait for samples to become available
            pause(0.02);
        end
        if s2.BytesAvailable
            try
                res1 = dataFromResult(fscanf(s2)); %read the angle and distance value into res1 = [angle, distanceValue]
                res = res1(2);    resAngle = res1(1);
            catch
                res=[];
                display('something went wrong!');
            end
            samplesRead = size(res,1);
            if samplesRead>0
                indexB = resAngle/SCAN_RESOLUTION+1;
                if indexB>0 && indexB<=180/SCAN_RESOLUTION+1
                    B(round(indexB)) = res;
                    plotVals = [(1000-B).*cos(theAngles') (1000-B).*sin(theAngles')];
                    plot(plotVals(:,1),plotVals(:,2),'-.');
                    hold on;
                    plot(plotVals(round(indexB),1),plotVals(round(indexB),2),'-gO');
                    hold off;
                    xlim([-1000 1000]); ylim([-100 1000]);
                    pause(0.000002);    %so the plot is updated
                end
            end
        end
    end
catch ME1
    ME1.message,ME1.stack,ME1.cause,fclose(s2);delete(s2);
end
try
    fclose(s2);delete(s2);clear s2
end
colordef white;
%% converts the result to a numeric row(kabraeck)
    function [ data ] = dataFromResult( result )
        remain = result;
        index=1;
        tokens=[];
        while (~isempty(remain))
            [token,remain] = strtok(remain, ',');
            if (index>1)
                tokens(index-1)=strread(token);
            end
            index=index+1;
        end
        data = tokens;
    end
end

The image below shows an example plot Matlab generates:

The green dot indicates the current measurement

The green dot indicates the current measurement

 You can see that there is an obstacle on the left of the robot. 

Below are two videos that are perhaps more illustrative:

Code download

You can download the complete code here. This is an Eclipse project (see my other article on how to use Eclipse for PIC development), but you can import the .c and .h files into MPlab if you like. Note that this project assumes to be loaded onto the PIC with an USB bootloader (see this article for details)!

May 9, 2009 at 5:49 pm Leave a comment

PIC servocontroller (in C)

In this article I’ll explain how to control a simple servo motor from a PIC18F4455 microcontroller. I am using a real cheap servo (an¬†ES-30, see Conrad site), but it should be enough for hobby (read: robot) purposes.

Servo Controller

A DC motor is controlled using a DC voltage, but a servo motor requires some more work as it is controlled using pulses. By varying the width of a pulse you can set the angle the servo motor has to turn to. A servo motor can usually turn from -90 degrees to +90 degrees, but my ES-30 seems to be limited to -70 to +70 degrees or so.. 

Connections

The servo motor has three connections: ground (black), supply voltage (red) and the connection for the input pulses (usually yellow). We will connect the black wire to ground, the red one to our PIC supply voltage (5V) and the yellow wire to the D3 output (PORTDbits.RD3). So D3 will be the PIC output pin that controls the servo.

servo

Pulses

The servo expects a pulse every 20ms. The width of this pulse varies in the range 1.0 Р2.2ms, this range could be different with your specific servo so consult the datasheet (or just try some values)! A pulse width of 1.0ms sets the servo to the far left, a pulse of 2.2ms to the far right, and everything in between should map on an angle somewhere in between. 

Timing with the PIC uC

We are going to use interrupts to ensure our pulses appear every 20ms. A timer interrupt happens when the timer register overflows. The timer register (can be configured as 8bit or 16bit) is increased on every clock tick. If the prescaler is set it happens less than every clock tick. A spreadsheet with my calculations is available at http://spreadsheets.google.com/pub?key=p9YPS93eEHH3W7dx5fxQEMQ&output=xls, you can see the interrupt rate for various settings of the prescaler value. 

You can enable the interrupts like this:

OpenTimer0(TIMER_INT_ON & T0_SOURCE_INT & T0_16BIT & T0_PS_1_4);	//enable TMR0, 16bit, CLK0 src, low-to-high trans, prescale on, prescale 1:4 

So your servo initialization will look like this:

void startServo(void) {		//initialize TIMER0 + enable interrupts
	TRISD				=	0;	//D is output
	PORTD				=	0;
	INTCONbits.RBIF		=	0;
	INTCONbits.TMR0IE	=	0;
	RCONbits.IPEN		=	0;
	OpenTimer0(TIMER_INT_ON & T0_SOURCE_INT & T0_16BIT & T0_PS_1_4);	//enable TMR0, 16bit, CLK0 src, low-to-high trans, prescale on, prescale 1:4 
	INTCONbits.GIE 		= 	1;	//enable global interrupts
	INTCONbits.PEIE 	= 	1;	// enable peripheral interrupts
}

Define the interrupt function like this:

 

 

#pragma interruptlow timerFtie
void 
timerFtie(void)  {
	if (INTCONbits.TMR0IF) {	//interrupt timer 0
		INTCONbits.TMR0IF = 0;	//interrupt flag off
		servoInterrupt();
	}
}

 

Now we only need to define what will happen inside the servoInterrup() function, i.e. the function that is called every time TIMER0 overflows. We will set D3 to the correct value (1 or 0) depending on whether the pulse is starting or ending. We will also initialize TMR0H and TMR0L to values so that the next overflow appears when a pulse needs to start/stop. This is explained in the following note:

servo1

This results in the following code:

void servoInterrupt(void) {	//called on overflow of TIMER0
	//create pulse (begin or end of pulse)
	PORTDbits.RD3 = (pulseOn == 1);
	//set new TIMER0 value
	if (pulseOn == 1) {
		pulseOn = 0;
		TMR0H = 0xFF & (pulseOnLoad >> 8);
		TMR0L = 0xFF & pulseOnLoad ;
	} else {
		pulseOn = 1;
		TMR0H = 0xFF & (pulseOffLoad >> 8);
		TMR0L = 0xFF & pulseOffLoad;
	}
}

PulseOnLoad and PulseOffLoad are set according to the servo angle:

void setServoAngle(short angle) {	//set new servo value (called from external code)
	short loadTimer0BeginPulse 	= 0;
	short loadTimer0EndPulse 	= 0;
	short usPulse;
	short timerCount;	// [2727,6363] =~ [900,2100]*3
	servoAngle = angle;
	usPulse = MIN_PULSE_DURATION + angle*((MAX_PULSE_DURATION-MIN_PULSE_DURATION)/180);
	timerCount = usPulse * 3;	//0.33us = 1/3 us per tick
	pulseOnLoad = 65534 - timerCount+2;
	pulseOffLoad = 5538 + timerCount +2;
}

Code download

You can download the complete code here. This is an Eclipse project (see my other article on how to use Eclipse for PIC development), but you can import the .c and .h files into MPlab if you like. Note that this project assumes to be loaded onto the PIC with an USB bootloader (see this article for details)!

References

 

  • This site¬†gives a very thorough introduction to using a servo with a PIC12F675, though all code is not freely available. My logic is also a bit different: I don’t wait inside the interrupt routine untill the end of the pulse but I set it low using a second interrupt.¬†
  • http://www.mcmanis.com/chuck/robotics/projects/servo.html¬†gives another introduction to using the servo with a PIC, the code is in assembler.
  • The PIC datasheet, chapter about TIMER0.¬†

May 2, 2009 at 4:38 pm 1 comment


Feeds

Articles to be written…

Twitter – kr3l

my del.icio.us

RSS Google Reader Shared Stuff

  • An error has occurred; the feed is probably down. Try again later.

RSS Listening to..

  • An error has occurred; the feed is probably down. Try again later.