Laser spot detection

Hi everyone !

I’m working on a project where the main goal is to get the coordinates (in pixels) of multiple laser spots in outside environment. I’m using the OpenMV H7 module as development kit and I have multiple questions.
The previous step I did was using the OpenCV library on a computer with the camera directly connected. Now, I’m trying to make it an embedded system.

I know that it’s not possible to use OpenCV with MicroPython, so I looked in the OpenMV libraries and I didn’t found what I did in my previous algorithms which were manipulating image like converting the all image in a certain color domain (YUV for me). So, I was thinking to make my own C library and link it to the firmware of the OpenMV H7.

I have only basic knowledge about microcontrolers and Python, and the combination of both isn’t very documented ^^.

So here are my questions :

  • The OpenMV H7 uses the OV7725, is it possible to use another CMOS with only re-writing the associate driver or does it require a larger modification on the OpenMV libraries ? (I was planning to have the IMX290, mainly for the high fps output in HD mode)
  • I was planning to use brutal calculation on the whole image, but maybe the use of blobs would be better or any other method ? (The illumination parameters aren’t constant as it’s in an outdoors environment) And if so, I don’t really understand them ? (I can check on documentation, but if you have something ready to send :smiley: )
  • The convertion to other color spaces is not implemented, do we have to use the commands “image.add”, “image.sub”… To compute them ?
  • As I may create my own C library (in further development or other project), how can we implement it into the microcontroler ? Is saw in the wiki page that you use QtCreator to do the development and many steps are detailed, is it what can permit us to add our own modules ? (I run on Windows but I have a dual boot possibility with Ubuntu)

Finally, I had some issues to control my lasers with PWM mode.

Here is my code :

class Foo(object):
    def __init__(self, timer):
        timer.channel(1, Timer.PWM, callback=self.cb, pulse_width_percent=50)
        timer.channel(2, Timer.PWM, callback=self.cb2, pulse_width_percent=5)

    def cb(self, timer):
        LED(1).toggle()

    def cb2(self, timer):
        LED(2).toggle()
        
obj = Foo(pyb.Timer(3, freq=1))

The cb functions are used on the LEDs, but it can be on the pins too (just have to adapt the code), the fact is that I want to change the intensity of lights with the pulse_width_percent argument. (Here it’s at 1Hz to see if the pulse_width_percent is effective) But when I run the code, I don’t see :

  • LED1 + LED2 on : 5%
  • LED1 on : 45%
  • both LED off : 50%
    But I see, in this order :
  • LED1 : 25%
  • LED1+LED2 : 25%
  • LED2 : 25%
  • both LED off : 25%
    Is that normal behaviour ? Did I miss something ?

When I control only 1 LED, with f=1kHz, I can’t control its intensity with the pulse_width_percent in the way it is coded. I have to add “timer.callback(self.cb)”, which is redondant with the line “timer.channel(…”. Is it normal ? Does it mean that I can’t control the intensity of 2 lasers on different Pins with different methods with the same timer ? (As I need to add the timer.callback function) So, here is my last question : what is the difference between the timer and the channel ? (Do they have to get the same callback function ?)

I know I have many questions and thanks a lot for what you do, and for your answers !

Regards,
Florian

Howdy, please use the find_blobs() method to track a laser spot.

Regarding all your questions for color conversion, the OpenMV Cam works on an RGB565 image. Because it s a microcontroller without a lot of RAM we don’t convert the color space of the image. Instead, our algorithms work on the pixels directly and then convert the image into another color space (the LAB color space which is like YUV) as each pixel is accessed. This is all done through the find_blobs() method. image — machine vision — MicroPython 1.15 documentation

Please look at the find_* methods on the OpenMV Cam. You basically don’t want to use any of the basic math methods. Those are there for very specific image masking cases and not much else.

If you need to keep illumination consistent please adjust the image exposure or use a method like histeq() which can change the image contrast.

Regarding a higher res camera, no, you can’t connect an IMX290. Our processor is not capable of hooking up to that sensor nor handling the raw image bandwidth. The design of the OpenMV Cam was to offer high speed vision processing that is easy to get up and running. Our goal was never to push the resolution limits.

Regarding your PWM question… if you read what your code is doing you put a timer callback on a function that toggles an LED, the pulse_width_percentage will not change the frequency at which the callback is called, only the duty cycle of the signal.

I see that you are trying to PWM the LED onboard the OpenMV Cam. The onboard LED doesn’t really support PWM however. You can PWM an LED attached to an I/O pin however.

Anyway, can you describe your problem in a clear way? Maybe I can point you in the right direction.

Hi,

I want to command the laser seen by the camera in PWM mode in order to make some calculation by triangulation. The camera will be mounted in sort that there is not fixed background and illumination. The lasers will come from the embedded device (alongside with the camera), and I was planing to command their intensity with PWM (In order to have a signal/noise quotient high enough).

I tried some variations in the code; but there’s something I don’t understand : I will use 4 lasers spots. In the case I want to have 2 lasers with less intensity than the 2 others, I’ll have to put them on different pins but I’m using the same timer (and different channels). Even though, changing the duty cycle should change the intensity, with the control of the 2 pins separated. Well… That’s I want to do, but may be it’s not possible.

Here is the (new) code :

class laserPWM(object):
    nb = 0

    def __init__(self, pin):
        laserPWM.nb += 1
        pin.init(mode = Pin.OUT_PP, pull = Pin.PULL_UP)
        self.pin = pin
        self.timerLaser = Timer(2, freq=1000)
        self.timerLaser.callback(self.laserToggle)
        self.channel = self.timerLaser.channel(laserPWM.nb, Timer.PWM, callback=self.laserToggle, pulse_width_percent=0)
        if self.pin.pull() == Pin.OUT_PP:
            print("Laser correctly configured in 3.3V")
        if self.pin.mode() == Pin.OUT_PP:
            print("Laser correctly configured as an output")

    def laserToggle(self, timer):
        if self.pin.value():
            self.pin.value(0)
        else:
            self.pin.value(1)

    def intensity(self, value):
        self.channel.pulse_width_percent(value)

    def off(self):
        self.pin.value(0)

laser1 = laserPWM(Pin("P5"))
laser1.intensity(k1)
laser2 = laserPWM(Pin("P6"))
laser2.intensity(k2)

And here is what is going on :
When I set k1 <= k2, both lasers are at maximal power. (Even if I set them at 5)
When I set k1 > k2, laser2 is at the good intensity but laser1 is at maximal intensity.
That makes me think that we can’t use the same timer for 2 different pins, am I write ?

I think you’re having issues because you are trying to control the PWM in software when it’s a hardware timer process. The PWM example doesn’t use a callback to set the PWM signal. It’s entirely driven by the hardware.

Okay, Ibrahim in the last firmware update reserved timer 4 and in the next firmware he will unreserve it. Timer 4 is typically what I’ve used for PWM.

You have an H7 right? I’ll just give you the lastest firmware with some example code.