Menu

Line following robot

Help
2007-01-26
2013-05-30
  • Nobody/Anonymous

    Hello, sorry to keep bothering you guys with these questions:
    I want to make a simple line following robot, using some LED IR emitter and detectors. I want to use a PIC 16F628A or 16F684. I really have no idea how to get started -- but hopefully there will be some kind of tutorial someone can point me to, or give me some information.

    I really have no clue how to set up the emitter and detector to detect the line -- is it even possible?

    Thanks
    Omar

     
    • Hugh Considine

      Hugh Considine - 2007-01-29

      Some links:
      http://www.fastcharged.org/robotics/firstrobot
      http://www.diylive.net/index.php/2005/12/13/diy-line-following-robot2/

      I'd recommend that you use the 16F684, as it has an A/D converter in it that will make reading the sensors much easier.

      From personal experience, it is better to use visible LEDs and LDRs or phototransistors to detect the line. Because the light is visible, it is easier to see if everything is aligned properly.

      For the programming code, have a look at http://gcbasic.sourceforge.net/newfiles/analog%20line.txt

       
    • Nobody/Anonymous

      Thank you very much for that. I checked out the information, and it helped a lot. Now I have a few questions:

      The code you gave me from the demo files, is for a specific robot kit, and frankly I'd rather build my own, so would you by any chance have code snippets of a line detecting program in Great Cow Basic? Pretty please? I actually like this method better (CDS cell and LED), and it seems that calibrating would be easier.

      As for the chip, that is no problem. In fact I accidentally bought a few of those chips anyway so it seems it'll work out. Yay for not wasting micro controllers =D

      Now any ideas how I can drive a motor from the pins? It seems not enough current is being supplied... and I have heard I need some kind of driver. I think the author of the linked tutorial isn't using a driver, how can he get away with it?

      Thanks a lot, your help means a lot!
      Omar

       
    • Nobody/Anonymous

      Okay, well I have tried to figure stuff out on my own -- I don't want to bug you for everything. So here is how far I have gotten. I have decided to use the IR detector and sensor for now, as it seems easier to program.

      -----------------------------------
      #chip 16F684, 8
      dir PORTC.0 OUT
      dir PORTC.1 OUT
      dir PORTC.2 IN
      dir PORTA.0 IN

      'Put the sensor on the right side of the line
      SET PORTC.0 ON
      SET PORTC.1 ON

      Start:
      IF ReadAD (PORTA.0) > 3.5 THEN
          SET PORTC.1 ON
          SET PORTC.0 OFF
      IF ReadAD (PORTA.0) > 3.5 THEN
          SET PORTC.0 ON
          SET PORTC.1 OFF
      goto Start

      --------------------------
      PORTC.0 is my right motor
      PORTC.1 is my left motor
      I use the readAD function to get the measurement from the detector. Basically, you set it on the right side of the line (the robot's detector), and the robot starts to go left, as soon as it detects white space, it turns right, and then it follows that pattern. Of course, it isn't that snazzy -- quite static actually. But I think it may be simple enough to work. Can you spot and obvious errors in my code?

      As for the motor, I tried using the motor driver that http://www.diylive.net/index.php/2005/12/13/diy-line-following-robot2/ the author made (schematics posted in the article). It seems to make my motor run, but when I was testing it with simple on/off code, the timing was going crazy. Such as the motor is supposed to turn on for 10 seconds, and then turn off, while another pin turns on at this point. But the motor would stay on for 3 seconds, and the other pin for the rest of the time. Could it be feedback from the motor messing up the microcontroller? Do you recommend anything to fix this??
      Thanks for your help!
      Omar

       
    • Nobody/Anonymous

      Sorry, not meaning to bump for no reason, but does anyone have any replies for that last post?

       
    • Hugh Considine

      Hugh Considine - 2007-02-10

      There are several problems with your program:

      - It is trying to use the HS oscillator. This may be okay, but if you are trying to use the internal oscillator of the chip, you should add this line:
       
        #config INTRC_OSC_NOCLKOUT

      - ReadAD accepts AN0, AN1, AN2, etc as parameters. PORTA.0 would be confusing it completely - replace PORTA.0 with AN0 and it will be fine

      - GCBASIC cannot handle floating point numbers, so 3.5 would be confusing it. Change it to 3 or 4.

      - You need END IF at the end of the IF statements.

      I can't help you much with the hardware side of things - all I can recommend is that you have plenty of capacitors on the power supply pins of the PIC, and on each of the motors.

       
    • Nobody/Anonymous

      Aside from all of those, will it get confused that after the first initial going left-until-off-the-line, that it has to now go the other way until-off-the-line... will that cause a confusion?

      This is what I have so far, fixed. As for the hardware-- took your advice. Thank you!

      --------
      #chip 16F684, 8
      #config INTRC_OSC_NOCLKOUT

      dir PORTC.0 OUT
      dir PORTC.1 OUT
      dir PORTC.2 OUT
      dir PORTA.0 IN

      'Put the sensor on the right side of the line
      SET PORTC.1 OFF
      SET PORTC.0 ON

      Start:
      DO UNTIL ReadAD (AN0) > 3
          SET PORTC.1 ON
          SET PORTC.0 OFF
          LOOP
      IF ReadAD (AN0) > 3 THEN
          SET PORTC.1 OFF
          SET PORTC.0 ON
      DO UNTIL ReadAD (AN0) > 3
          SET PORTC.1 OFF
          SET PORTC.0 ON
          LOOP
      goto Start
      --------

       
    • Nobody/Anonymous

      Sorry, forgot one END IF...

      #chip 16F684, 8
      #config INTRC_OSC_NOCLKOUT 

      dir PORTC.0 OUT
      dir PORTC.1 OUT
      dir PORTC.2 OUT
      dir PORTA.0 IN

      'Put the sensor on the right side of the line
      SET PORTC.1 OFF
      SET PORTC.0 ON

      Start:
      DO UNTIL ReadAD (AN0) > 3
      SET PORTC.1 ON 
      SET PORTC.0 OFF
      LOOP
      IF ReadAD (AN0) > 3 THEN 
      SET PORTC.1 OFF
      SET PORTC.0 ON
      DO UNTIL ReadAD (AN0) > 3
      SET PORTC.1 OFF
      SET PORTC.0 ON
      LOOP
      END IF
      goto Start 

       
    • Nobody/Anonymous

      I'm sorry to bump, but I was wondering if that above code would work?

      Thanks for your help, I'm sorry to bump like this but I thought my post was forgotten.

       
    • Hugh Considine

      Hugh Considine - 2007-03-31

      Your code should work, try compiling and running it and see what happens.

      One thing that you could do to make the code easier to read is use indentation, like this:

      DO UNTIL ReadAD (AN0) > 3 
        SET PORTC.1 ON 
        SET PORTC.0 OFF 
      LOOP 
      IF ReadAD (AN0) > 3 THEN 
        SET PORTC.1 OFF 
        SET PORTC.0 ON 
        DO UNTIL ReadAD (AN0) > 3 
          SET PORTC.1 OFF 
          SET PORTC.0 ON 
        LOOP 
      END IF

      This makes it much easier to see if you have left out an END IF.

       
    • Nobody/Anonymous

      I am sorry. I've started to indent my code it does truly help. Just when I post it here the indents seem to disappear. I've decided to fix he code a little, and I've even made a calibration system so I can get the exact readings. If you don't mind, could you please look over it again? I copied the line following code and changed it a bit as per one of the demo files that were supplied.

      Thank you very much (I'll repost with just the code, so it is easier to see).

       
    • Nobody/Anonymous

      #chip 16F684, 8
      #config INTRC_OSC_NOCLKOUT

      ReadingOne = 0
      ReadingTwo = 0
      ReadingThree = 0
      ReadingFour = 0
      Reado = 0
      Readt = 0
      LINEo = 0
      LINEof = 0

      dir PORTC.0 OUT
      dir PORTC.1 OUT
      dir PORTC.4 OUT
      dir PORTA.0 IN
      dir PORTC.3 IN
      dir PORTC.2 IN

      IF PORTC.3 ON THEN CALIBRATE
      WAIT UNTIL PORTC.2 ON
      EPRead (0, LINEo)
      EPRead (1, LINEof)
      SET PORTC.1 OFF
      SET PORTC.0 ON

      START:
      IF ReadAD (AN0) >= LINEo THEN LEFT
      IF ReadAD (AN0) <= LINEof THEN RIGHT
      GOTO START

      SUB LEFT
          SET PORTC.1 OFF
          SET PORTC.0 ON
      END SUB

      SUB RIGHT
          SET PORTC.1 ON
          SET PORTC.0 OFF
      END SUB

      SUB CALIBRATE
          WAIT UNTIL PORTC.2 ON
              IF PORTC.2 ON THEN ReadingOne = ReadAD (AN0)
          WAIT UNTIL PORTC.2 ON
              IF PORTC.2 ON THEN ReadingTwo = ReadAD (AN0)
          WAIT UNTIL PORTC.2 ON
              IF PORTC.2 ON THEN ReadingThree = ReadAD (AN0)
          WAIT UNTIL PORTC.2 ON
              IF PORTC.2 ON THEN ReadingFour = ReadAD (AN0)
          wait 1 s
          Reado = (ReadingOne + ReadingTwo) / 2
          Readt = (ReadingThree + ReadingFour) / 2
          EPWrite (0, Reado)
          EPWrite (1, Readt)
          wait 1 s
              SET PORTC.4 ON
              wait 1 s
              SET PORTC.4 OFF
          WAIT UNTIL PORTC.2 ON
          EXIT
      END SUB

       
    • Hugh Considine

      Hugh Considine - 2007-04-01

      It looks pretty good, and should be okay except for two things. First, the EXIT on the second to last line doesn't say what to exit from.

      Also, there is an undocumented Average function that you could use instead of the division. It will run faster and use less code, plus it won't cause problems if the total of the two values exceeds 255. To use it, replace

      Reado = (ReadingOne + ReadingTwo) / 2
      Readt = (ReadingThree + ReadingFour) / 2

      with

      Reado = Average(ReadingOne, ReadingTwo)
      Readt = Average(ReadingThree, ReadingFour)

       
    • Nobody/Anonymous

      Oh, thank you very much! I was just wondering, do I need that exit function in that Calibration Sub, or will it automatically exit and go back to the part of code where it left of?

      That average function will really save me some headaches, I'm sure I would have gone insane when the line follower doesn't correctly work.

      One more thing, I didn't think that code above would work (the line following part) so I changed it to this. I'm not sure, logically both might work but I am leaning towards this one. Any ideas?

      START:
          DO WHILE ReadAD (AN0) >= LINEo
              SET PORTC.1 OFF
              SET PORTC.0 ON
          LOOP 
          IF ReadAD (AN0) <= LINEof
              SET PORTC.1 OFF 
              SET PORTC.0 ON 
              DO UNTIL ReadAD (AN0) <= LINEof
                  SET PORTC.1 OFF 
                  SET PORTC.0 ON 
              LOOP 
          END IF
          IF ReadAD (AN0) <= LINEof
              SET PORTC.1 ON 
              SET PORTC.0 OFF
          END IF
      GOTO START

       
    • Nobody/Anonymous

      Just one more question, will it matter if I decide to wait a few seconds between each calibration and button press-- will the value of the variable keep changing... like:

          WAIT UNTIL PORTC.2 ON
          IF PORTC.2 ON THEN ReadingOne = ReadAD (AN0)
                          SET PORTC.4 OFF
                          WAIT 2 s
                          SET PORTC.4 ON
          WAIT UNTIL PORTC.2 ON
          IF PORTC.2 ON THEN ReadingTwo = ReadAD (AN0)
                          SET PORTC.4 OFF
                          WAIT 2 s
                          SET PORTC.4 ON

      If I press the button, the variable value becomes the sensor reading. Now at this point the program flashes LEDs to tell me it worked so far... during that time if the sensor readings change does that mean the variable will keep on changing too?

       
    • Nobody/Anonymous

      i recommend using 3 sensors with the following algorithm pseudo code, i won the national titles with this(note this is pseudo code not gcbasic because i originally programmed in assember):
      if left sensor detects line:
           turn right until middle sensor detects it
      if right sensor detects line:
           turn left until middle sensor detects line
      this way, if the motor is going fast and by the time the line is detected its already over the line, it will just turn until it is found! , theoretically, no matter how fast you are going, you should still catch the line.

      ps: i suggest writing the calibration values to the onboard eeprom since this cant be reset to a pin value.

       
    • Mark Twomey

      Mark Twomey - 2008-09-08

      I have been doing experiments with a IR light sensor ( I bought a pack of IR emitter and IR detector from SparkFun for $2 part number SEN-00241)... That site has a link to basic circuitry for this IR detector.

      I have been doing some experimentation with sensing light using this detector.

      I have used the following code as a testbed for sensing and logging the data to the EEPROM in the chip (16F887). I then use the Read Chip feature in the MPLAB IDE to see the data stored in the EEPROM.

      Hope this helps.

      'Define Chip Model and its operating frequency in MHz
      #chip 16F887, 4

      'Define the Port Pin Assignments and my Descriptions
      #define MaintStatus PORTD.1  'Pin function RD1 as the cpu signal to show with Green Steady LED when in maintenance mode
      #define Activity PORTD.2  'Pin function RD2 as the cpu signal to show with Red Blinking LED of Activity
      #define InActive PORTD.3  'Pin function RD3 as the cpu signal to show with Green Blinking LED if Inactive

      'Analog PORT Definitions / Functions
      #define PLightMeter PORTA.0  'Pin 2 (RA0/AN0) function AN0 as the sensor to detect the light level

      'Define Analog Port Pin Functions
      #define LightMeter AN0

      'Other definitions
      #define half_sec 50 10ms 

      'Set the Port Pin Directions
      DIR MaintStatus OUT
      DIR Activity OUT
      DIR InActive OUT

      DIR PLightMeter IN

      '------------------- MAIN LOGIC -------------------

      Main:
         GOSUB set_ports
        
         GOSUB lead_in_warning
         GOSUB measure_light_level 1, 20
        
         GOSUB lead_in_warning
         GOSUB measure_light_level 21, 40
        
         GOSUB lead_in_warning
         GOSUB measure_light_level 41, 60
        
         GOSUB completion_lights
      END

      '---------------------------------------------------

      SUB set_ports
         ' Set OUT ports to OFF
         SET MaintStatus OFF
         SET Activity OFF
         SET InActive OFF
      END SUB

      SUB lead_in_warning
         'Indicate sampling is about to start
         FOR Data_count = 1 TO 10
            SET InActive ON 'Green
            SET Activity ON 'Red
            WAIT half_sec
            SET InActive OFF  'Green
            SET Activity OFF 'Red
            WAIT half_sec
         NEXT
      END SUB

      SUB measure_light_level (From_data, To_data) #NR
         'Do twenty lightmeter readings
         FOR Data_count = From_data TO To_data
            SET Activity ON 'Red
            WAIT half_sec
            SET Activity OFF 'Red
           
            'Do Measurement
            Light_level = ReadAD(LightMeter)
            EP_mem_addr = Data_count - 1 'eeprom addresses start at zero.
            EPWrite(EP_mem_addr, Light_level)
         NEXT
      END SUB

      SUB completion_lights
         SET MaintStatus ON 'Green
         SET InActive ON 'Green
      END SUB

       

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.