Archive for May, 2009

Free GPS tracker on handheld / pocket pc

I hacked my Medion GPS a few months ago so I could add other programs on the device using instructions from this site. But a simple application that I really wanted but just could not find was a GPS tracker, a program that logs your coordinates to a file. Last week I picked up my Medion again determined to find the missing application, and I found it ūüôā

The hacked gps with Windows CE desktop

The hacked gps with Windows CE desktop

The program gives information about the available GPS satelites

The program gives information about the available GPS satelites

The application is called NMEA Monitor CE and can be downloaded for free over here. For my Medion 95058 device (PNA150 model with Win CE 4.2) I needed the ARM H/PC Pro2.11 H/PC2000 download. Just copy the file to your device and run it over there.

Go to Option>Preferences and select your GPS’s COM port (on my Medion it is COM port 2). Then select File>save as and create a *.NME file. Now your coordinates are logged in NMEA format, so put that GPS in your backpack and go cycling for a while!

Once you come back all tired and sweaty you’ll want to check out the route you have cycled so copy the .NME file over to your pc. Now you’ll have to convert it to the *.kml format so you can view the route in Google Earth.

You can use GPSBabel, an open source program available at http://www.gpsbabel.org/download.html for this conversion.

The following screenshots show you the settings for converting the NME file to a kml file:

1

The Filter button reveals some other options (which you can ignore safely for now):

93f0a17845415e22fec495dd91b12658

Click on “let’s go” and your kml file is generated. Open the file in Google Earth and you’ll get a nice view of the track! Sidenote: The new Google Earth appears to have a cool time slider which makes it handy to view where your were at what time.

The route in Google Earth

The route in Google Earth

If you know of other handy free tools that run on a handheld pc (especially gps-related tools), let me know in the comments!

May 27, 2009 at 10:07 pm Leave a comment

Getting started with Fedora Repository

I recently had to get started with the Fedora Repository. Because the Fedora Commons site is somewhat chaotic, and a quickstart is hard to find online, I’ll write the basic steps in getting a Fedora Repository up and running here.¬†

fedora_commons

What is it?

First of all, the Fedora Repository has nothing to do with the famous Linux distro (there actually was some dispute over the trademark). Fedora Repository is an open source digital repository management system, originating at the Cornell University in 1998 and open source since 2003. The current release is Fedora 3.2. 

The repository is meant to store (or link to) digital assets (images, video, audio, … anything really) and their related metadata.¬†For example, I am using Fedora as a repository for video files. The video files are available in different formats (high resolution, low resolution flash video, …) and there is an XML file per video describing the video contents.¬†

This article describes the setup of the repository, the data model Fedora uses, and how to interact with the repository using Java and Ruby.

Installation

First download the latest version of Fedora from their site (go to Developers > Downloads). As mentioned before, the current release is fedora-installer-3.2.jar. When installing you can choose between the quick and the custom installation. Choose the latter, because we want to enable the REST interface. Go to the download location in your terminal and type

java -jar fedora-installer-3.2.jar

to start the installation process. The default options are ok except that you should enable the REST api. More information on the installation is available here.

Fedora comes runs inside a tomcat server. After installation you can start Fedora by going to fedora_home/tomcat/bin and typing in a command line (Linux / Mac)

sh catalina.sh run

or (Windows)

startup.bat

You should see some messages that indicate that tomcat is starting up and that Fedora is being deployed and the final message should say something like “server startup complete”. Now you can fire up your browser and surf to http://localhost:8080/fedora. If everything went well, an ugly page showing some info about Apache Axis.

The Fedora data model

A Fedora object contains several datastreams

A Fedora object contains several datastreams

The image on the right shows a Fedora object. It has a unique ID called the PID (persistent ID) and some other properties. A Fedora object also contains so-called datastreams. These contain the actual data. This data can be the essence (e.g., the video material) or the metadata about this essence (e.g., an XML file with descriptions). 

Fedora has some default datastreams (RELS-EXT, DC and AUDIT), and the user can add as many other datastreams as necessary. So what do these default datastreams contain?

  • The RELS-EXT datastream contains the relationships to other objects in the repository. This can for example contain a relationship “is part of” that states that this object is part of another object (e.g. a collection “news videos”).
  • The DC datastream contains Dublin Core metadata about the object. Dublin Core is a metadatastandard with some basic fields (like title, author etc.), so this stream is a basic description of the object’s contents.
  • The AUDIT datastream contains the history of actions performed on the object.
  • The other datastreams could contain the different versions of a video file (High resolution version, low resolution, audio channels, …). Datastreams can also contain more metadata (e.g., a NewsML XML file).

You can find more information about the datastreams in tutorial 1 on the Fedora site.

Fedora offers a number of cool features, like versioning datastreams (so you can go back to a previous version of a datastream, e.g. when someone messed up the metadata describing a videofile). It is also possible to define transformations of your datastream using webservices. If you have for example a webservice that can convert an image to grayscale, you could couple this to Fedora and it would be like your object had an extra datastream that contained the grayscale version, but actually when this datastream is called a grayscale version would be created on the fly. 

Adding your first objects

The best way to get started with Fedora is using the client administrator program that is included in the installation (fedora_home/client/bin/fedora-admin). 

This is explained in tutorial2 on the Fedora site: tutorial2, so I won’t go into detail. You really should follow this tutorial as it gives a good overview of Fedora’s possibilities. The image below shows a screenshot of the application:

The Fedora Administrator application

The Fedora Administrator application

With the application you can add new objects to Fedora. 

Connecting to Fedora with Ruby

ruby_logo

The Fedora repository exposes two types of interfaces to the outside world: a SOAP API and a REST API. The latter is the simplest and we’ll start with it to demonstrate access from within a Ruby script to Fedora.¬†

The guys at¬†http://www.yourmediashelf.com/¬†have created two Ruby gems for communication with Fedora: RubyFedora and ActiveFedora (homepage). RubyFedora is a Ruby wrapper around the Fedora REST interface and is the gem we’ll be using in this paragraph. ActiveFedora tries to provide an ActiveRecord-like experience when using Fedora from Ruby, I haven’t tested this gem yet.¬†

Start by installing the RubyFedora gem:

gem install ruby-fedora

Use the following Ruby script (fill in your username, e.g., fedoraAdmin, and password in the repository url) to create a new object, save it and find it back:

#!/usr/local/bin/ruby
require 'ruby-fedora'
repository = Fedora::Repository.register('http://user:pass@localhost:8080/fedora')
test_object = Fedora::FedoraObject.new(:label => 'honolulu', :contentModel => 'Image', :state => 'A', :ownerID => 'fedoraAdmin')
repository.save(test_object)
objects = repository.find_objects('label~Image*')
object = repository.fetch_content('demo:1')

(The last line will result in an error if a file with pid equal to demo:1 does not exist)

The following is a more elaborate example that will print some of the object’s fields and will also print some of the fields of the Dublin Core datastream:

#!/usr/local/bin/ruby
require ‘ruby-fedora’
require ‘rexml/document’
#connect to the repository
repository = Fedora::Repository.register(‘http://fedoraAdmin:test@localhost:8080/fedora’)
#create a new object
test_object = Fedora::FedoraObject.new(:label => ‘blublub’, :contentModel => ‘Video’, :state => ‘A’, :ownerID => ‘fedoraAdmin’)
#save the object
repository.save(test_object)
#find objects with pid video* (e.g., “video:1” / “video:2” / … )
vids = repository.find_objects(‘pid~video*’)¬†
vids.each { |video|
¬†¬†#print this item’s fields
¬†¬†puts video.pid.to_s ¬† ¬† + “\n******************\n”
¬†¬†puts “create_date … ” + video.create_date.to_s ¬† ¬† ¬†+ “\n”
¬†¬†puts “modified_date … ” + video.modified_date.to_s ¬† ¬† ¬† + “\n”
¬†¬†puts “state … ” + video.state.to_s ¬† ¬† + “\n”
¬†¬†puts “label … ” + video.label.to_s ¬† ¬† + “\n”
¬†¬†puts “owner_id … ” + video.owner_id.to_s ¬† ¬† + “\n”
# ¬†puts “profile … ” + video.profile.to_s ¬† ¬† + “\n”
  
  #extract Dublin Core datastream
  xml_data = video.object_xml
  doc = REXML::Document.new(xml_data)
  root = doc.root
¬†¬†dc_field = root.elements[“foxml:datastream[@ID=’DC’]/foxml:datastreamVersion/foxml:xmlContent/oai_dc:dc”]
¬†¬†puts “\n” + dc_field.elements[“dc:identifier”].text + ” => ” + dc_field.elements[“dc:title”].text
}
#!/usr/local/bin/ruby
require 'ruby-fedora'
require 'rexml/document'
#connect to the repository
repository = Fedora::Repository.register('http://fedoraAdmin:test@localhost:8080/fedora')
#create a new object
test_object = Fedora::FedoraObject.new(:label => 'blublub', :contentModel => 'Video', :state => 'A', :ownerID => 'fedoraAdmin')
#save the object
repository.save(test_object)
#find objects with pid video* (e.g., "video:1" / "video:2" / ... )
vids = repository.find_objects('pid~video*') 
vids.each { |video|
  #print this item's fields
  puts video.pid.to_s     + "\n******************\n"
  puts "create_date ... " + video.create_date.to_s      + "\n"
  puts "modified_date ... " + video.modified_date.to_s       + "\n"
  puts "state ... " + video.state.to_s     + "\n"
  puts "label ... " + video.label.to_s     + "\n"
  puts "owner_id ... " + video.owner_id.to_s     + "\n"
  #puts "profile ... " + video.profile.to_s     + "\n"
  #extract Dublin Core datastream
  xml_data = video.object_xml
  doc = REXML::Document.new(xml_data)
  root = doc.root
  dc_field = root.elements["foxml:datastream[@ID='DC']/foxml:datastreamVersion/foxml:xmlContent/oai_dc:dc"]
  puts "\n" + dc_field.elements["dc:identifier"].text + " => " + dc_field.elements["dc:title"].text
}

Connecting to Fedora with Java

296946221_6ef6d4e99b

(Duke image taken from here). The Fedora installation comes with a client demo illustrating some of the things you can do with the SOAP interface. It is located at Fedora_Home\client\demo\soapclient. To create a project in Eclipse with this code, start up Eclipse and add the following libraries to your build path: fedora_home/client/fedora-client-3.1.jar and everything in fedora_home/client/lib/. Add the DemoSOAPClient.java file to your project and use the functions in it in your own code. For example, the following code will add an item to Fedora based from a FOXML file.

 

 

public static void addToFedora(String filename,long theID) {
//FEDORA REPO
DemoSOAPClient caller;
try {
	caller = new DemoSOAPClient("http", "localhost", 8080, "fedoraAdmin", "test");
	//RepositoryInfo repoinfo = caller.describeRepository();
	//delete item if it exists
	String purgeDate=null;
	try {
		purgeDate = caller.purgeObject(
			"id:"+theID, // the object pid
			"purge object", // an optional log message about the change
			 false);  // do not force changes that break ref integrity
	} catch (Exception e) {
		//System.out.println("Hack...just ignore failures since objects may not exist yet." + e.getMessage());
	}

	//add the item to Fedora
	FileInputStream inStream=null;
	String ingestPID=null;
	File ingestFile=new File(filename);
	try {
		inStream=new FileInputStream(ingestFile);
	} catch (IOException ioe) {
		System.out.println("Error on ingest file inputstream: " + ioe.getMessage());
		ioe.printStackTrace();
	}
	System.out.println(" - ingest FoXML in Fedora");
	try {
	        ingestPID = caller.ingest(inStream, fedora.common.Constants.FOXML1_1.uri, "ingest of item");
	} catch (IOException ee1) {
		System.out.println("Error during ingest: "+ee1.getMessage());
		//ee1.printStackTrace();
	}
	//System.out.println("Finished test ingest of sdef object: " + ingestPID);
} catch (Exception e1) {
	// TODO Auto-generated catch block
	e1.printStackTrace();
}
}

That’s it for this Fedora introduction!

May 24, 2009 at 2:34 pm 10 comments

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.