Posts tagged ‘PIC18F’

Bluetooth communication between BlueSMIRF and Ubuntu

A quick post on how to set up the Bluetooth communication between Ubuntu and a BlueSMIRF Modem.

My laptop was broken recently, and after getting a free new motherboard from the kind Sony people I reinstalled Ubuntu and tried to get all my software running again. Today I tried setting up the Bluetooth communication with my toy car’s BlueSMIRF (see previous posts) and  my laptop, and decided on documenting it. So here’s how to do it:

  1. (optional) It’s easiest if you can see what is happening on the BlueSMIRF side. Therefore, you’ll need a serial (TTL) to USB convertor like this one. Alternatively, if you have a Dwengo board (or similar), you can use that one by simly removing the PIC18F chip for a while:

    Now you can monitor the commands and data passing through the BlueSMIRF by opening “serial port terminal” (install it through the Ubuntu Software Center) on /dev/usbtty0 at the speed of your BlueSmirf (default 115200 baud)

    Details on the commands available are available in the Roving Networks Command datasheet.

  2. I didn’t get the default Ubuntu Bluetooth tool (the B in the taskbar) to play nice with the BlueSMIRF, so I installed “Bluetooth Manager” (BlueMan) through the Software Center.
  3. Power the BlueSMIRF, it should start blinking rapidly for about a minute. This means it is waiting for a connection. Once the rapid blinking stops, you can’t connect anymore!
  4. Click on the B in your taskbar of BlueMan, a window should open showing the Bluetooth devices in your environment. One of them should be FireFly (the BlueSMIRF). Right click on it an select “connect to SPP”:

    (the name in the screenshot is robot-719A instead of Firefly because I changed it earlier)
  5. Because this is the first time you connect to the BlueSMIRF, it needs to be paired. Therefore, Blueman will ask you the pass phrase. Enter “1234” (without quotes), this is the default passphrase of the BlueSMIRF.
  6. The bottom of the Blueman screen should now say “Serial port connected to /dev/rfcomm0”. Now you can open a serial connection to /dev/rfcomm0 using serial port manager (or from within a script) and start communicating 🙂
    The LED on the BlueSMIRF should turn green.

That’s it! Now the pairing is done, and you won’t need to enter the passphrase the next time you connect to the BlueSMIRF.

    Advertisements

    December 19, 2010 at 11:15 am Leave a comment

    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

    Communication with Pinguino via Bluetooth

    I bought a BlueSMIRF Bluetooth module a few weeks ago, and this weekend I’ve finally had some time to put it in action 🙂

    Connecting the BlueSMIRF module is really easy. The BlueSMIRF module has 6 pins: CTS-I, VCC, GND, TX-0, RX-1 and RTS-0. You have to connect CTS-I to RTS-0, connect VCC to the supply voltage and GND to ground. The TX-0 pin is connected to the RX pin of the microprocessor, while the RX-1 pin is connected to the TX pin of the microprocessor. On the PIC18F4455 these are pins 26 and 25 (pinguino pins 9 and 8). s

    CTS-I  O----------------
    VCC    O--5V           |
    GND    O--0V (gnd)     |
    TX-0   O-- to RX PIC   |
    RX-1   O-- to TX PIC   |
    RTS-0  O----------------

    As explained in a previous post, I am using a Pinguino board, so the code should work on Arduino as well without needing too many modifications. This is the code I used for writing some text:

    #define PIC18F4550
    char incomingByte = 'K';	// for incoming serial data
    
    void setup() {
      Serial.begin(115200);
    }
    
    void loop() {
    	// send data only when you receive a C character
    	if (Serial.available() > 0) {
    		// read the incoming byte:
    		incomingByte = Serial.read();
    		if (incomingByte == 'C') {
    			Serial.print("I received: ");
    			Serial.print(incomingByte, DEC);
    		}
    	}
    }
    In the setup routine I connect to the serial port at 115200 bauds. The bluetooth module is just used as a regular serial cable, so no fancy tricks are necessary.
    On my Ubuntu laptop, I had to do the following to get things running:
    • first connect your Bluetooth dongle to the BlueSMIRF (mine appeared as FireFLY-719A)
    • sudo hcitool scan #so we know the MAC address of the FireFLY
    • rfcomm connect 0 00:06:66:03:72:9A #substitute with your BlueSMIRF’s MAC address
    • sudo gtkterm -p /dev/rfcomm0 -s 115200 #start gtkterm to read/write to the serial port

    Of course we don’t want to interact through gtkterm with our microcontroller. I wanted to employ Processing, but this gave some additional difficulties in my setup. In Processing, Serial.list() is used to list all available serial ports. The Bluetooth serial port /dev/rfcomm0 does not appear in the list though. A dirty hack to solve the issue is symlinking /dev/ttyS0 to /dev/rfcomm0:

    sudo rm /dev/ttyS0
    sudo ln -s /dev/rfcomm0 /dev/ttyS0

    If anyone knows a better way to solve the issue, please mention so in the comments! This is the Processing code:

    import processing.serial.*;
    
    Serial myPort;                // Create object from Serial class
    
    void setup()
    {
      size(200, 200);
      myPort = new Serial(this, Serial.list()[0], 115200);  //the first port in the list is /dev/ttyS0 which we symlinked to /dev/rfcomm0
    }
    
    void draw()
    {
      while (myPort.available() > 0) {                      //if something was received via serial port
        String inBuffer = myPort.readString();
        print(inBuffer);
      }
    }
    
    void keyPressed() {
      print(key);
      myPort.write(key);
    }
    
    void stop() {
      myPort.stop();
    }

    February 22, 2010 at 6:12 pm 3 comments

    Using Dwengo board as a Pinguino

    The Pinguino project is a relatively new project that tries to build an Arduino-like project with a PIC processor. The project comes with a nice and simple IDE and a bootloader so programs can be placed on the PIC very easy.  I found the Dwengo board I own is compatible with the Tiny-4550 Pinguino board, so it is possible to use the Pinguino IDE and bootloader with the Dwengo board. 

    Here are the steps I followed on my Ubuntu (Karmic) machine to get things fired up:

    • Install wxPython as explained here
    • Download the latest Pinguino IDE from the hackinglab dowload index. Extract the archive. Run the IDE by running the pinguinobetax.py Python script from the terminal. Put sudo before it to run it with administrator rights, because otherwise you’ll get a ”Could not change device” error! The IDE looks like this:

    • With the PIC18F4550 we need the second version of the bootloader (see Pinguino tutorial site). It can be dowloaded here. To put the bootloader on your PIC, I used xwisp, which is a Windows program (I ran it in a Virtualbox virtual machine).
    • Once the bootloader is on your PIC, connect your board via a USB cable to your PC. Hold the reset button and the “up” button on your board, then release the reset button. The bootloader program knows you want to place a program on it now.
    • Open up the Pinguino IDE and type e.g. this program in it:
    // Testing input with Pinguino
    // jean-pierre MANDON 2008
    // modified kr3l for DWENGO
    #define PIC18F4550
    void setup() 
    {
    pinMode(0,INPUT);         //button
    pinMode(21,OUTPUT);    //led
    }
    void loop() 
    {
    if (digitalread(0)) digitalWrite(21,HIGH);
    else digitalWrite(21,LOW);
    }
    The pin numbers used here are as in the Tiny-4550 schematic:
    so pin 21 as used in the program is actually pin 19 of the PIC processor.
    • press the compile button, then the “put program on pinguino” button. The program starts running after a few seconds. If you press the center button one of the leds will go off.

    I think the Pinguino project is a really cool initiative and I hope they keep working on it. More experiments will be conducted soon!

    December 31, 2009 at 3:35 pm 1 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

    Older Posts


    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.