Shop OBEX P1 Docs P2 Docs Learn Events
Using Parallax Laser Rangefinder as a camera. - Page 2 — Parallax Forums

Using Parallax Laser Rangefinder as a camera.

2»

Comments

  • BeanBean Posts: 8,129
    edited 2011-10-12 05:36
    Here is a new version of the viewer program.
    It shows crude grayscale at the top and the "U" and "V" channels at the bottom.
    Try holding different solid color object to the camera and see the "U" and "V" results.
    Red has a "light" affect on the "V" channel.
    Blue has a "light" affect on the "U" channel AND a "dark" affect on the "V" channel.
    CON
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000 
      tiles    = vga#xtiles * vga#ytiles
      tiles32  = tiles * 32
    
      SerRxPin      = 0              ' Serial interface connect to Sout on LRF
      SerTxPin      = 1              '                  connect to Sin on LRF
    
    OBJ
    
      vga : "vga_512x384_bitmap"
      ser : "JDCogSerial"                         ' Full-duplex serial communication (Carl Jacobs, http://obex.parallax.com/objects/398/)
    
    
    VAR
    
      long  sync, pixels[tiles32]
      word  colors[tiles]
    
    
    PUB start | h, i, j, k, x, y, value
    
      ser.Start(|<SerRxPin, |<SerTxPin, 19200) ' Start JDCogSerial cog
    
      'start vga
      vga.start(16, @colors, @pixels, @sync)
    
      'init colors
      repeat i from 0 to tiles - 1
        colors[i] := $FC00 ' White on black
    
      waitcnt(cnt+clkfreq)
      ser.Tx("U")
      waitcnt(cnt+clkfreq)
    
      repeat
        waitcnt(cnt+clkfreq/4)
        ser.RxFlush
        ser.Tx("Y")
        y := 0
        repeat 80
          x := 0
          repeat 64
            value := ser.Rx ' Read Y1
            plotGS(x, y, value)
            value := ser.Rx ' Read U
            plotGS(x>>1, y+170, value)
            value := ser.Rx ' Read Y2
            plotGS(x+2, y, value)
            value := ser.Rx ' Read V
            plotGS(x>>1+138, y+170, value)
            
            x += 4
          y += 2
    
    PRI plotGS(x, y, value)
      if value > 51
        plot(x, y)
      else
       unplot(x, y)
      if value > 102
        plot(x+1, y+1)
      else
        unplot(x+1, y+1)
      if value > 153
        plot(x+1, y)
      else
        unplot(x+1, y)
      if value > 204
        plot(x, y+1)
      else
        unplot(x, y+1)
      
    
    PRI plot(x,y)
    
    '  if x => 0 and x < 512 and y => 0 and y < 384
       pixels[y << 4 + x >> 5] |= |< x  
    
    PRI UnPlot(x,y)
    '  if x => 0 and x < 512 and y => 0 and y < 384
        pixels[y << 4 + x >> 5] |= |< x  
        pixels[y << 4 + x >> 5] ^= |< x  
    
    

    Bean
  • ratronicratronic Posts: 1,451
    edited 2011-10-12 10:05
    I know this picture isn't very good but your viewer works for me using your firmware. At first I thought it did just a frame grab until I stood in front of the LRF and found out it is constantly updating.
    640 x 480 - 95K
  • BeanBean Posts: 8,129
    edited 2011-10-12 10:23
    Dave,
    Nice. If you hold up a large blue object you should see a pattern in the U and V fields.

    I am working on a new version that will capture a frame and then let the remote request the data one line at a time. This will allow you to communicate much faster by using a buffer to store 1 line, process it, then request another line. The lines can be requested in any order. So you can just request the line you are interested in. Requesting a line > 79 terminates the command.

    I'd also like to allow the single line data to be returned in RGB format (16-bit or 24-bit). I'm working on that part now.

    Bean
  • ratronicratronic Posts: 1,451
    edited 2011-10-12 10:42
    Talk about a fancy line scanner! I thought I would post some pixs I took of the uOLED and the view the LRF was looking at. That device is so small it was hard to get a good picture. Also a pix of my current setup.
    640 x 480 - 118K
    640 x 480 - 67K
    640 x 480 - 96K
  • BeanBean Posts: 8,129
    edited 2011-10-12 11:32
    Dave,
    Here is the latest version that returns lines in RGB (8-bits each, 384 bytes per line).
    CON
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000 
      tiles    = vga#xtiles * vga#ytiles
      tiles32  = tiles * 32
    
      SerRxPin      = 0              ' Serial interface connect to Sout on LRF
      SerTxPin      = 1              '                  connect to Sin on LRF
    
    OBJ
    
      vga : "vga_512x384_bitmap"
      ser : "JDCogSerial"                         ' Full-duplex serial communication (Carl Jacobs, http://obex.parallax.com/objects/398/)
    
    
    VAR
    
      long  sync, pixels[tiles32]
      word  colors[tiles]
      byte cameraline[128*3]
    
    
    PUB start | x, y, i, value, lineNo
    
      ser.Start(|<SerRxPin, |<SerTxPin, 115200) ' Start JDCogSerial cog
    
      'start vga
      vga.start(16, @colors, @pixels, @sync)
    
      'init colors
      repeat i from 0 to tiles - 1
        colors[i] := $FC00 ' White on black
    
      waitcnt(cnt+clkfreq)
      ser.Tx("U")
      waitcnt(cnt+clkfreq)
    
      repeat
        ser.Tx("Z")
        y := 0
        repeat lineNo from 0 to 79
          ser.rxFlush
          ser.Tx(lineNo)
          repeat i from 0 to 383
            cameraLine[i]:=ser.Rx
          x := 0
          i := 0
          repeat 128  ' 128 pixels per line
            value := cameraLine[i++] ' Read r
            plotGS(x, y, value)
            value := cameraLine[i++] ' Read g
            plotGS(x+256, y, value)
            value := cameraLine[i++] ' Read b
            plotGS(x+128, y+170, value)
            x += 2
          y += 2
        ser.Tx(255)
    
        
    PRI plotGS(x, y, value)
      if value > 51
        plot(x, y)
      else
       unplot(x, y)
      if value > 102
        plot(x+1, y+1)
      else
        unplot(x+1, y+1)
      if value > 153
        plot(x+1, y)
      else
        unplot(x+1, y)
      if value > 204
        plot(x, y+1)
      else
        unplot(x, y+1)
      
    
    PRI plot(x,y)
    
    '  if x => 0 and x < 512 and y => 0 and y < 384
       pixels[y << 4 + x >> 5] |= |< x  
    
    PRI UnPlot(x,y)
    '  if x => 0 and x < 512 and y => 0 and y < 384
        pixels[y << 4 + x >> 5] |= |< x  
        pixels[y << 4 + x >> 5] ^= |< x  
    

    Bean
  • ratronicratronic Posts: 1,451
    edited 2011-10-12 11:50
    Here is me holding a blue plastic cover in front of the LRF using your lastest software in post#36.
    640 x 480 - 68K
  • ratronicratronic Posts: 1,451
    edited 2011-10-12 12:11
    Bean you have commented in the firmware that the 'Z' command returns a 120 x 85 frame but 384 bytes per line/3 = 128 pixels?
  • BeanBean Posts: 8,129
    edited 2011-10-12 12:42
    I need to fix that. The resolution is 128x80 now.

    Bean
  • ratronicratronic Posts: 1,451
    edited 2011-10-12 15:41
    I couldn't get a good picture of the uOLED but heres a color pix on uOLED and a normal shot of the room as the lrf would see it. There is a dark colored bookcase on the right hand side that probably should be dark or black show blue on the uOLED. But other than that everything else looks natural.
    Con                                                          
     
      _CLKMODE = XTAL1 + PLL16X                              
      _XINFREQ = 5_000_000  
      ack     = $06                                         ' Acknowledge byte      
      nak     = $15                                         ' Invalid command byte  
     
    Var
      byte cameraline[128*3]
     
    Obj                                                      
      db : "pcfullduplexserial"
      fd : "fullduplexserial"  
    Pub start| i,j,x,y
      fd.start(6, 7, 0, 115200)                             '
      db.init                                                
      db.addport(0, 31, 30, -1, -1, 0, 0, 19200) 'debug port 
      db.addport(1, 4, 5, -1, -1, 0, 0, 115200) 'uoled       
      db.start                                               
      waitcnt(clkfreq*3+cnt)
      fd.rxflush
      fd.tx("U")
      repeat until fd.rx == ":"
      db.str(0, string("Camara online",13))
      db.rxflush(1)                              
      db.tx (1, "U")
      waitack
      db.str(0, string("uOLED ready",13)) 
      waitcnt(1600000+cnt)
      erase
      repeat   
        get
     
    Pub waitack 
     
      repeat until db.rx(1) == ack
     
    Pub erase                                            
      db.tx (1, "E")    
      waitack
     
    Pub get | i, r, g, b, x, y, z
      fd.tx("Z")
      repeat y from 0 to 79
        fd.rxflush
        fd.tx(y)
        repeat i from 0 to 383  
          cameraline[i]:=fd.Rx
        i := 0      
        repeat x from 0 to 127
          r := cameraline[i++]   
          g := cameraline[i++]    
          b := cameraline[i++]     
          plot(x, y, r, g, b)     
     
    Pub plot(x, y, r, g, b)                                                 
      '     X : 0 to 127                              
      '     Y : 0 to 127                              
      '   Red : 0 to 255                              
      ' Green : 0 to 255                              
      '  Blue : 0 to 255                              
     
      r := r >> 3 << 11 | (g >> 2 << 5) | (b >> 3)    
      db.tx(1, "P")                                 
      db.tx(1, x)                                   
      db.tx(1, y)                                   
      db.tx(1, r.byte[1])                           
      db.tx(1, r.byte[0])                           
      waitack
    
  • BeanBean Posts: 8,129
    edited 2011-10-13 05:12
    Dave, Yeah I can't really see anything in the picture.

    By "everything else looks natural" you mean the image color look good ?

    I've noticed that sometimes black shows blocks of white (full on), but I have the variables limited so I can't tell why it does that sometimes. That may be the blue you are seeing instead of black.

    Try to get a better picture of the oLED if you can. I'd love to see a color image.

    Bean
  • BeanBean Posts: 8,129
    edited 2011-10-13 06:11
    Dave,
    Here is a version of the viewer that shows color objects.
    CON
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000 
      tiles    = vga#xtiles * vga#ytiles
      tiles32  = tiles * 32
    
      SerRxPin      = 0              ' Serial interface connect to Sout on LRF
      SerTxPin      = 1              '                  connect to Sin on LRF
    
    OBJ
    
      vga : "vga_512x384_bitmap"
      ser : "JDCogSerial"                         ' Full-duplex serial communication (Carl Jacobs, http://obex.parallax.com/objects/398/)
    
    
    VAR
    
      long  sync, pixels[tiles32]
      word  colors[tiles]
      byte cameraline[128*3]
    
    
    PUB start | x, y, i, r, g, b, lineNo
    
      ser.Start(|<SerRxPin, |<SerTxPin, 115200) ' Start JDCogSerial cog
    
      'start vga
      vga.start(16, @colors, @pixels, @sync)
    
      'init colors
      repeat i from 0 to 6*16
        if i & 15 < 8
          colors[i] := 3<<14 ' red
        else
          colors[i] := 3<<12 ' green  
    
      repeat i from  5*16 to 12*16-1
        colors[i] := 3<<10 ' Blue
        
      waitcnt(cnt+clkfreq)
      ser.Tx("U")
      waitcnt(cnt+clkfreq)
    
      repeat
        ser.Tx("Z")
        y := 0
        repeat lineNo from 0 to 79
          ser.rxFlush
          ser.Tx(lineNo)
          repeat i from 0 to 383
            cameraLine[i]:=ser.Rx
          x := 0
          i := 0
          repeat 128  ' 128 pixels per line
            r := cameraLine[i++] ' Read r
            g := cameraLine[i++] ' Read g
            b := cameraLine[i++] ' Read b
            ' Only show the strongest color
            if (r > g) and (r > b) 
              plotGS(x, y, r)
            else
              plotGS(x, y, 0)   ' Plot R
            if (g > r) and (g > b)  
              plotGS(x+256, y, g) ' Plot G
            else
              plotGS(x+256, y, 0)  
            if (b > r) and (b > g)  
              plotGS(x+128, y+170, b) ' Plot B
            else
              plotGS(x+128, y+170, 0)  
            x += 2
          y += 2
        ser.Tx(255)
    
        
    PRI plotGS(x, y, value)
      if value > 51
        plot(x, y)
      else
       unplot(x, y)
      if value > 102
        plot(x+1, y+1)
      else
        unplot(x+1, y+1)
      if value > 153
        plot(x+1, y)
      else
        unplot(x+1, y)
      if value > 204
        plot(x, y+1)
      else
        unplot(x, y+1)
      
    
    PRI plot(x,y)
    
    '  if x => 0 and x < 512 and y => 0 and y < 384
       pixels[y << 4 + x >> 5] |= |< x  
    
    PRI UnPlot(x,y)
    '  if x => 0 and x < 512 and y => 0 and y < 384
        pixels[y << 4 + x >> 5] |= |< x  
        pixels[y << 4 + x >> 5] ^= |< x  
    

    Bean
  • ratronicratronic Posts: 1,451
    edited 2011-10-13 08:15
    Bean I finally burned out my uOLED last night. This was my second one and I knew about their problems of removing power before issueing a power down command. I had taken many pictures of the uOLED but that was the best one. Looking at it in person except for the blue everything else in the picture the color tones looked as they did in real life. When I turned the LRF to a spot with no dark places in it the whole picture looked natural. I also have a C328 camera so I will be looking for another serial color display device without the problem posted below. Have any suggestions?
    1024 x 530 - 92K
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2011-10-13 09:01
    Good grief! Software (or the lack thereof) should never be allowed to damage the hardware that it drives. Would it have been so hard for the uOLED designers to include an automatic power-down sequencer? Hewlett Packard discovered this the hard way on their HP85 desktop computer that had a built-in thermal printer. Problem was, the thermal printhead was controlled in software by the main microprocessor. A bug in the user's software could cause the printhead to overheat and burn out, since there was no hardware one-shot to limit the "on" time.

    -Phil
  • BeanBean Posts: 8,129
    edited 2011-10-13 10:20
    Dave, to put it bluntly "NOT COOL!!!" that is a terrible design flaw.

    Bean
  • ercoerco Posts: 20,253
    edited 2011-10-13 13:51
    Good grief! Software (or the lack thereof) should never be allowed to damage the hardware that it drives. -Phil

    Agreed. HOWEVER, one of my back burner projects is just to make an LED clock. Dull and boring, but I want to do the LED multiplexing directly using my 16 little IO pins. A good challenge. Trouble is, the duty cycle is so low (like 1/24) that I have to overdrive each LED segment just to make it bright enough to see. Which means driving the LED segment directly (and briefly) from the IO pin's 5V with no resistor. No problem as long as the program keeps running. But if & when the program stops execution (code error? Moi?) during development, I'm likely to release the magic smoke from the IO pin. Oh sure, I could use an optoisolator buffer for protection, but where's the fun in that?
  • ratronicratronic Posts: 1,451
    edited 2011-10-13 13:56
    I am trying right now to communicate between RobotBasic and the LRF. RobotBasic has bit mapped graphics and serial communication on the computer so it may take me a while to see if I can do it that way.
  • ratronicratronic Posts: 1,451
    edited 2013-06-23 12:44
    The new LCD Parallax sells should display a 8 bit grey scale image from the camera on the laser range finder.using this program. I have a different model than Parallax's but it is the same type. So anybody that happens to have both give this a try. Bean I am using the original firmware's "G" command and it puts out 160 x 128 not 176 x 144 as it describes for GR_X and GR_Y. I might have to take a look again at your firmware and see if I can attain color results.

    Edit: The LCD display uses RGB565 but this program converts the 8bit grey scale from the camera to the LCD's RGB565.
    Con                          'display picture from Parallax laser range finder to 4D systems ulcd
                                                               
      _CLKMODE = XTAL1 + PLL16X                              
      _XINFREQ = 5_000_000
      
      ACK = 6
      LCD_RX = 17  'input from lcd transmit pin
      LCD_TX = 16  'output to lcd receive pin
      LRF_RX = 15  'input from laser range finder transmit pin
      LRF_TX = 14  'output to laser range finder receive pin
      
    Var
      byte buffer[20480]
      
    Obj
      lcd : "fullduplexserial"
      lrf : "fullduplexserialplus" 
         
    Pub Main
        
      lcd.start(LCD_RX, LCD_TX, 0, 115200)   
      lrf.start(LRF_RX, LRF_TX, 0, 115200)
      
      lrf.tx("U")
      repeat until lrf.rx == ":"
      lcd.tx($ff)
      lcd.tx($cd)
      get_ack
      display_frame
      
    Pub Get_Ack                    
                                     
      if lcd.rxtime(1000) == ACK   
        return true                                                                              
      else                       
        return false             
    Pub Display_Frame | i, r, g, b, x, y
      lrf.rxflush
      lrf.tx("G")
      
      i := 0
      repeat
        buffer[i++] := lrf.rx
        if i > 20480
          waitcnt(350000 + cnt)
          lrf.rxflush
          quit
     
      i := 0
      lcd.rxflush 
      repeat y from 0 to 127
        repeat x from 0 to 159
          r := g := b := buffer[i++]
          put_pixel(x, y, r, g, b)
                  
    Pub Put_Pixel(x, y, r, g, b) | color                                         
                                                   
      color := r >> 3 << 11 | g >> 2 << 5 | b >> 3 
      lcd.tx($ff)                                  
      lcd.tx($c1)                                  
      lcd.tx(x >> 8)                               
      lcd.tx(x)                                    
      lcd.tx(y >> 8)                               
      lcd.tx(y)                                    
      lcd.tx(color >> 8)                           
      lcd.tx(color)                                
      get_ack
    
  • ratronicratronic Posts: 1,451
    edited 2013-06-24 11:33
    Here is a slightly improved version. Got rid of not needed stuff but this version takes 30 seconds to completely display a picture from the time you hit F10. That's because this version sets up the camera for it's current environment (white balance etc). It does

    print the picture faster to the screen as it ignores the ACK's for the Put_Pixel method. I believe the first version if you comment out the get_ack in the Put_Pixel method you can get a picture to print in less than 20 seconds but you have to take a couple of

    pictures in a row to get the white balance etc.setup. This also prints a message to the screen asking you to wait.
    Con                          'display picture from Parallax laser range finder to 4D systems ulcd
                                                               
      _CLKMODE = XTAL1 + PLL16X                              
      _XINFREQ = 5_000_000
      
      ACK = 6
      LCD_RX = 17  'input from lcd transmit pin
      LCD_TX = 16  'output to lcd receive pin
      LRF_RX = 15  'input from laser range finder transmit pin
      LRF_TX = 14  'output to laser range finder receive pin
      
    Var
      byte buffer[20480]
      
    Obj
      lcd : "fullduplexserial"
      lrf : "fullduplexserialplus" 
           
    Pub Main
      
      lcd.start(LCD_RX, LCD_TX, 0, 115200)   
      lrf.start(LRF_RX, LRF_TX, 0, 115200)
      
      clear_screen
      put_string(@splash)
      
      lrf.tx("U")
      repeat until lrf.rx == ":"
      
      lrf.tx("E")
      repeat until lrf.rx == ":"
      
      clear_screen
      display_frame
    Pub Clear_Screen
      lcd.tx($ff)
      lcd.tx($cd)
      repeat until lcd.rx == ACK
    Pub Display_Frame | i, r, g, b, x, y
      lrf.tx("G")
      
      i := 0
      repeat
        buffer[i++] := lrf.rx
        if i > 20480
          repeat until lrf.rx == ":"
          quit
     
      i := 0
      repeat y from 0 to 127
        repeat x from 0 to 159
          r := g := b := buffer[i++]
          put_pixel(x, y, r, g, b)
      waitcnt(clkfreq/100 + cnt)    
      lcd.rxflush
        
    Pub Put_Pixel(x, y, r, g, b) | color                                         
                                                   
      color := r >> 3 << 11 | g >> 2 << 5 | b >> 3 
      lcd.tx($ff)                                  
      lcd.tx($c1)                                  
      lcd.tx(x >> 8)                               
      lcd.tx(x)                                    
      lcd.tx(y >> 8)                               
      lcd.tx(y)                                    
      lcd.tx(color >> 8)                           
      lcd.tx(color)                                
    Pub Put_String(str)
      lcd.tx($00)
      lcd.tx($18)
      lcd.str(str)
      lcd.tx($00)
      repeat until lcd.rx == ACK
    Dat
    Splash  byte  "Please wait for camera to",13,10,13,10,"   setup & take picture",0
    
Sign In or Register to comment.