Close
0%
0%

Laser Projector

Laser projector with 3 lasers (RGB) incident on an x-cube(dichroic) with galvanomirror

Public Chat
Similar projects worth following
In an attempt to create multi coloured beams of laser combined and then projected onto the screen with a galvanomirror and an stm32 microcontroller. I'm building majority of things from scratch by reading research papers and with the help of past projects. This being my final year project i'm hoping to get scientific on this.


  • Successful Projection of Combined beam

    Shoaib Mustafa11/22/2024 at 08:10 0 comments

    Aligning the beam took a bit of time as aligning all three horizontally and vertically first required that the beams were straight. tested each laser beams vertical height and horizontal shift with a ruler. 

    Then incident that beam on to the galvanomirror and tried to centre the beams again by making sure that all the beams were almost incident on the same point at one of the mirrors of the galvo. 

    This alignment would have been way easier if done with individual dichroic mirrors.

    I then proceeded to implement the algorithm of raster scanning with a single beam at constant voltage, and then with three beams at constant voltage (not PWM) I got a bright white light that had a bit of a blueish hue to it because of the much higher intensity of the blue and green laser compared to the red which was almost hidden in the resultant light. 

    This is how my setup looked with everything working.. I chose to put a aperture to limit the beam width  right in front of galvo which was a bad idea.. i then moved it post galvo for better results. 

    with the algorithm working i projected a rectangle and a circle on the screen and these were the results. 

    rectangle with RGB white light (blueish hue)

    and a circle. 

    We can see a clipping at the bottom i'm not sure why that is.. will test more.. 

    The idea that we can project any shape to it is a proof that we can project anything onto it using the bitmap methodology. and with this i conclude the demonstration part of my project. I'll still be working on making it better and will try to project a complete image or a  5 second video on it, but that will take some time. 

    This was all done as part of my final year project at "CMND: centre for micro and nano devices" facility at COMSATS, Islamabad by me (Shoaib Mustafa) under the supervision of my supervisor: Dr. Mujtaba Hussain, mujtaba.hussain@comsats.edu.pk

    feel free to reach out at shoaib.mustafa7@hotmail.com

    follow my youtube:

     https://www.youtube.com/@capistor1 for more details and following videos.

    here is the github where i'll be uploading all the material. https://github.com/manhoosbilli1/Laser_Projector

    I hope you had fun!

  • Laser Holder Done!

    Shoaib Mustafa11/22/2024 at 05:29 0 comments

    I've been experiment with the design of the laser holder, since there was no open source design of it so i've decided to make it myself. 

    We started with this holder as inspiration. Though it would have been better to make it with aluminium for finer control but acrylic sheet is all we had available. 

    First started with a basic vertical alignment with having a plate that was curved from the bottom edge and added two screws such that they were opposite to each other with a spring for providing tension. When one of the screws is tightened, it pushes the vertical plate a bit forward curving the laser beam up or down. 

    Here is the auto cad design of it which was laser cut. Note this is only for the top and bottom plate but not the vertical.  

    Before fitting the screws here's how it looked. 

    For the bottom plate added two plates on top of each other where was one attached to the holder and was fixed, the other one on top is movable. it also has two screws opposite to each other providing tension and works on the same principle as the vertical one. 

    This gave us the ability to align the beam and to correct its inherent bending of the beam due to the structural drawback of the laser. 

    This holder was integral in aligning the beam on the xcube. 

    There are a few things that could have been better, instead of having a hex nut embedded in the plastic a brass insert would have been better. Instead of having the plates lying directly on to the other plate it would be nice if they were free to provide finer control. 

  • The next hurdle

    Shoaib Mustafa09/16/2024 at 15:21 0 comments

    I've been experimenting with the setup trying to make the galvo movement as smooth as possible and for this i've been successful in implementing a triangle wave generator on the DAC with DMA, i've gotten the results and compared with the interrupt based output which was limited to 300 Hz, with DMA however i've tested the wave output to 200KHz, This creates many different opportunities for me. First i can rest assured that the microcontroller is not being the bottleneck and concurrent processing in the stm32 while the SCAN mechanism is running. 

    I've discovered that the DMA has callbacks which i can use such as half-complete or full-complete. This allows us to change the one half of the array while the other half is being output. this way we can keep the lookup table updated. but i don't think we will need this as we just need a constant scanning mechanism. 

    I've also gotten a bit better in the stm32cubeide, now i can use the debugging features such as live variables and use the debugger better. I also understand that an easy way to look for available functions is to look in the header file and use that. not everything is defined in reference manual or data sheet. 

    I faced a problem while generating the triangle wave with DMA on the DAC; the wave had some weird peaks showing 

    I tried to fix it by doing several things such as adding a bypass capacitor, low pass filter but it couldn't be fixed. in addition to the wrong waveform, the frequency it was showing was also wrong, almost triple of the calculated frequency. I then fixed it by changing the word size of the DMA from word to half word. this fixed the issue. 

    I've also gotten hold of some better lasers which i've connected the power supply to by directly connecting to it's + and - also i'm working on developing a holder for the laser. before we use kinematic mirror mounts which allowed to make minute adjustment in x and y direction. but since this new laser is larger we can't fit it in there. 

    The laser looks heavy stuff but it's just a slightly better laser than the usual pointer. I wouldn't be surprised if the same diode is used here as well. 

    Right now I'm looking into somehow triggering the 2nd dac used for Y axis steering when the X axis DAC triangle wave is completed by using the complete callback. 

  • Implemented Algorithm On Hardware

    Shoaib Mustafa08/21/2024 at 22:04 0 comments

    After implementing the code on hardware the following were the results:

    I created a lookup table of around 100-256 samples with values increasing from 0-4095 to represent an incremental increase in the voltage of around (50-124px representing a pixel). Then that lookup table was fed to the DAC via Interrupt routine in stm32cubeide and also implemented on stm32duino with just a normal for loop to test the difference. However the results were almost the same. 

    The scanning done horizontally was going quite good it showed a straight line and i confirmed that it is working by slowing the scan speed of the galvo so i could see it jumping to each different pixel. The problem was that it took quite a bit of time coming from top to bottom as expected because the y axis dac was supposed to increment after the horizontal (x-axis) scan was complete. I deleted all delays but still results were the same. 

    It is my understanding that no matter what i do doing it through the CPU might be slow for whatever reason, maybe the DAC is being notified late or value executed late. I have my clock speed of the peripheral and system clock speed at 72Mhz (maximum available) but this is still the case.  the following are my assumptions without looking too deep into it. 

    Some Calculations

    To estimate the time it takes to output a single value from RAM to the DAC using a for loop on the STM32 F3 Discovery board, we need to consider several factors:

    1. CPU Clock Speed: The STM32F3 Discovery board typically runs at a default clock speed of 72 MHz.
    2. Instruction Cycles: The number of clock cycles required for each instruction in the for loop, including loading the value from RAM, and writing it to the DAC.
    3. Memory Access: The time to access the RAM and the DAC registers.

    Estimation Steps

    1. CPU Cycles per Operation:
      • Load from RAM: Typically takes 2 cycles.
      • Write to DAC: Writing to a peripheral register usually takes 2 cycles.
      • For Loop Overhead: The loop counter increment, comparison, and branching take additional cycles (around 3-4 cycles depending on optimization).
    2. Total Cycles per Loop Iteration: Let's assume each operation (loading and writing) takes around 2 cycles, and the loop overhead is about 4 cycles. This gives us approximately:Total Cycles=2(load)+2(write)+4(loop overhead)=8 cyclesTotal Cycles=2(load)+2(write)+4(loop overhead)=8 cycles
    3. Execution Time Calculation:
      • With a 72 MHz clock, each cycle is 1/ (72×10^6)  seconds, or approximately 13.89 ns.
      • So, the time per loop iteration is:
      Time per iteration=8×13.89ns ≈ 11.1ns, So that's approximately 11.1 microseconds for a whole sweep of values.

    But that is assuming that the galvo's can follow the speed at which signal is given. So i'm sure now that the microcontroller is not the issue. It has to be the bulky mirrors slowing everything down. I wouldn't be surprised if it skips a couple of values as it is reaching the specified position. 

    Further Investigation:

    My galvo's are the generic ones sold in amazon but i got it from aliexpress, Looking at the specification it has the rating of 15kpps so that should give us around 66.67 microseconds for each step. now that's still not surprising, our whole sweep which was running at full speed completely taking around 11.1 microseconds, the galvo is being a bottleneck which is around 6 times slower. 

    In addition to that according to specifications my galvo can sweep an angle of +-20 degrees with an input signal range of +-5V, since my signal is only 0 - 3.3V that gives me an angle range of  ≈6.6 degrees for the whole range.  This is good because the smaller range it is the lesser momentum it will build and easier for it to put a stop to it's motion. 

    There seems to be a problem in my understanding because if the galvo's response rate is truly 6 times slower that means the galvo should not even jump to the next point, instead...

    Read more »

  • Simulation Worked!

    Shoaib Mustafa08/17/2024 at 02:09 0 comments

    Well never a better feeling than what you thought might work actually works. After reading up more on some computer graphics turns out the mechanism with which i want to project and which was implemented on CRT tvs is called "Raster scanning" but i couldn't find any documentation of it or any work that had implemented this on galvos. after searching a bit more it turned out that this is a pretty common method and is usually hidden from public because i mean who even thinks about how characters are printed to the screen. I found some people utilizing windows.h api to print to screen from scratch and found some old commodore_64 era programs that used terminal as a screen. Most of all Javid from youtube with his game engine videos on command line helped alot.

    Here is the code.

    #include <stdio.h>
    #include <unistd.h>  // for usleep()
    
    // Define the Pixel struct
    typedef struct {
        int x;          // Position of the pixel in x
        int y;          // Position of the pixel in y
        int dac;        // Voltage value to be fed to DAC
        int intensity;  // Brightness level
        int color[3];   // RGB color options
    } Pixel;
    
    // Define the Settings struct
    typedef struct {
        int pixelDelay;  // Delay between drawing each pixel in microseconds
        int gridSize;    // Size of the grid (number of pixels per side)
    } Settings;
    
    // Hardcoded bitmap for the 8x8 grid with a 4x4 square in the center
    // 1 represents pixels to be drawn (green), 0 represents non-pixels (red)
    const int bitmap[8][8] = {
        {0, 0, 0, 0, 0, 0, 0, 0},
        {0, 0, 0, 0, 0, 0, 0, 0},
        {0, 0, 1, 1, 1, 1, 0, 0},
        {0, 0, 1, 1, 1, 1, 0, 0},
        {0, 0, 1, 1, 1, 1, 0, 0},
        {0, 0, 1, 1, 1, 1, 0, 0},
        {0, 0, 0, 0, 0, 0, 0, 0},
        {0, 0, 0, 0, 0, 0, 0, 0}
    };
    
    // Function to initialize the grid from the bitmap
    void initializeGrid(Pixel grid[], int gridSize, const int bitmap[8][8]) {
        for (int y = 0; y < gridSize; y++) {
            for (int x = 0; x < gridSize; x++) {
                int index = y * gridSize + x;
                grid[index].x = x;
                grid[index].y = y;
                if (bitmap[y][x] == 1) {
                    // Pixel value
                    grid[index].dac = 99;
                    grid[index].color[0] = 0;   // Green
                    grid[index].color[1] = 255; // Green
                    grid[index].color[2] = 0;   // Green
                } else {
                    // Non-pixel value
                    grid[index].dac = 0;
                    grid[index].color[0] = 255; // Red
                    grid[index].color[1] = 0;   // Red
                    grid[index].color[2] = 0;   // Red
                }
            }
        }
    }
    
    // Function to print the grid with colors and simulate delay per pixel
    void printGrid(const Pixel grid[], int gridSize, int pixelDelay) {
        printf("Grid:\n");
        for (int y = 0; y < gridSize; y++) {
            for (int x = 0; x < gridSize; x++) {
                int index = y * gridSize + x;
                // ANSI escape codes to set the text color
                printf("\033[48;2;%d;%d;%dm", grid[index].color[0], grid[index].color[1], grid[index].color[2]);
                printf("  "); // Print a space to represent the pixel
                // Reset text color
                fflush(stdout);
                printf("\033[0m");
                // Simulate delay between printing each pixel
                usleep(pixelDelay);
            }
            printf("\n");
        }
    }
    
    int main() {
        Settings settings;
        settings.gridSize = 8;        // Size of the grid (8x8)
        settings.pixelDelay = .2 * 1000000; // Delay between each pixel in microseconds (0.2 seconds)
    
        // Define a grid to hold a single image
        Pixel grid[settings.gridSize * settings.gridSize];
    
        initializeGrid(grid, settings.gridSize, bitmap);  // Initialize the grid from the bitmap
    
        printGrid(grid, settings.gridSize, settings.pixelDelay);  // Display the grid
    
        return 0;
    }
    

     . Alt Text 

    The raster projection I should say is working quite well. I've created each pixel to have position in the x,y a value which i'm calling dac value which is the actual voltage level where these pixels will correspond. For now these are just numbers. Then assigning each pixel intensity and colors. When i convert this to real galvo system i'll have to add in delta_v (voltage difference) and hope to calculate next pixel position with this. Then will first try to make it work with intensity. Possibly creating a shade of green laser along a line should be cool. The pixel delay or "Dwelling time" Is not just adding a delay here...

    Read more »

  • Thinking about Projection Algorithm

    Shoaib Mustafa08/11/2024 at 20:20 0 comments

    I'm pausing the experimental setup to plan the next steps:

    1. Laser Scanning Mechanism: Develop a method to control the laser, activating it only at designated points of interest.
    2. Color Mixing: Explore techniques for combining laser colors to produce RGB hues.

    Initial Approach: I'll begin by researching papers on similar laser scanning mechanisms. My goal is to synchronize laser activation with the galvo mirror's feedback, ensuring precise targeting. I plan to implement functions on a microcontroller (starting with C on a computer) to draw horizontal lines by specifying certain parameters. Greater control over these functions will help me understand and refine the system.

    Planned Functionality:

    • Accept an array, length, and pixel data of points.
    • Provide feedback after each point is successfully drawn.
    • Draw primary and mixed colors using either hex codes or RGB values.
    • Control the speed, frequency, and direction of line drawing.
    • Map Cartesian coordinates to real-world positions and vice versa.
    • Convert line length from millimeters to pixel size.
    • Generate process analytics, including time remaining, points left, and completion percentage.

    Objective: The function will be integrated into the galvo's horizontal scanning mechanism, allowing it to draw lines while maintaining a fixed vertical angle. After completing a horizontal scan, the system will increment vertically and repeat the process. The idea is to synchronize the horizontal scanning and line drawing mechanisms, enabling the precise rendering of an image, such as a vector or bitmap, in a line-by-line fashion.

    Here is how it should look like. say we are given an image which after being processed looks like a vector image or a bitmap to make it simple.

    byte customChar[] = { B01110, B10001, B10001, B01110, B10001, B10001, B10001, B01110 }

    Real_Setup

    All I have to do is when I know that the galvo is at the top vertical position i.e, top right (0,0) and scans horizontally towards right, it should go something like this

    pixelTobePopulated()? DrawPixel(): skip();
    

    The result should be a pattern like this: FTTTF (T for true, F for false). Initially, I'll hard-code a bitmap or vector image, adjusting it to fit the system's screen size and limits.

    While researching, I found a helpful video that demonstrated a similar approach. If this works, I could explore the archives of old CRT TVs or early system source codes to understand their scanning methods.

    Once I determine where the dots land, I'll focus on projecting different colors or mixtures using an RGB LED approach. However, that's a later step.

    To simulate the process and test code changes in real-time, I'll use the command line as my simulation monitor, controlling the cursor like the galvo's position to replicate dot placement. This approach is reminiscent of early programming exercises, like drawing shapes on the screen.

    After completing these steps, I can address issues like refresh rates, FPS, and the time delay for dots to remain in position before moving.

    Lastly, I want this project to be portable so I can experiment outside the lab. This means creating a portable optical table, similar to the one in my lab, by using CNC to drill holes and threads to secure the components. Achieving proper beam alignment is challenging, and moving the project to another optical table could complicate things.

  • Galvo's arrived!

    Shoaib Mustafa08/11/2024 at 20:12 0 comments

    Real_Setup I decided to go with this galvo set for a few reasons

    • It offers 20Kpps which is not high and we don't need it for first prototype this brings the cost down.
    • It offers 20 degrees of travel on each galvo.
    • Comes with a driver board already compatible with the feedback of the galvo. Saves me some work.
    • The mounting for the galvo is pre made and it provides us with 3 standard holes of size m4 to attach it to my optical bench.
    • The galvo's itself are standard so there will be alot of help available online.

    After looking into the galvos a bit, the inner construction of each galvo was found to be very simple. Comprised of two coils on opposite ends, the shaft of the mirror having permanent magnet on it. Some feedback ciruitry, usually light detecting diodes that will change it's value depending on the mirror. Providing it information about the direction it's travelling and the current position.

    The galvos work with a differential signal of 15V (so -15V to +15V) capable of detecting millivolts fluctuation and there about (I'm not really sure about this claim).

    The driver board is there to take care of the nitty-gritty of the galvo, it's feedback, making sure it is where we want it to be. Keeping account of the inertia of the mirrors, sweeping up an angle at different speeds, staying locked in at an angle are all parts of the functions offered by the driver board. It has two identical blocks of circuitry on the PCB, one for X axis control the other for Y. the rest of the connectors are for input of +15 and -15 so that the galvo will receive this signal. And the inputs for the DAC signal.

    The board requires an analog signal as per my knowledge. For that, the STM32F3 discovery board offers DAC (Digital to analog) peripheral. This is a 12 bit dual system perfect for controlling both X and Y. capable of driving them simultaneously with the help of DMA (Direct memory access), more on these terms later. This allows us to vary the analog signal between 0 - 4069 values. However, it seems like this is still not a differential signal because it goes from 0 - +3.3V with that many steps. I believe the driver board itself will be responsible for generation a differential signal from this? Or would we have to provide. I still have to figure this out.

    A few days later:  Galvo's are working Finally!

    The Galvo's seem to be very straight forward. After contacting the manufacturer and doing some testing on my own i couldn't figure out the connectors on the board and what they do, luckily I found multiple projects where people used the same galvo. but amongst them all this detailed https://hackaday.io/project/165977-laser-galvo-clock/log/164901-frame-driver-schematics article proved to be most helpful. I realised the board i had accepted a signal of +-5V max by finding a listing on amazon of the same board.

    A problem soon arose because the board needed a bipolar signal (+-5V) instead of the usual (0-5V). I found out that using a combination of 2 opamps in a certain configuration helps you amplify the signal i was providing (0-3.3V) to (0-5V) and it would add a dc offset to the signal; where usually the signal is offset from 0V now i would get the signal offset from -5V this would create a range of 10. The board then takes that voltage and converts it to appropriate +-15V for the galvo, while also adding in feedback and driving mechanism into the signal to make sure that the mirror is oriented according to the signal.

    I didn't know much about opamps and even after https://www.ti.com/lit/an/sloa097/sloa097.pdf up on it a bit and copying the circuit provided in the article i couldn't make sense of this application so decided to not use it and postpone it. Had this been successful it would have permitted me to use the full range of the galvo of around 20-25 degrees. But that would also make the calculations difficult and frankly much more time taking.

    By not using the bipolar signal and using the galvo's in such a configuration where...

    Read more »

  • Minimizing no of instruments

    Shoaib Mustafa08/11/2024 at 20:01 0 comments

    Let's sit and think about the number of instruments i have to automate and the data that i actually need.

    • wavelength of light doesn't change with duty cycle. it should in theory just behave the same way but only the brightness should increase or decrease. so i can get away with manually getting the data of each individual laser light.
    • Optical power of laser light. i'm not sure how that would be useful in creating a relation between the color and laser input values but i should get it because thats the kind of data that will be varying.
    • Thanks to Dr. Faisal for pointing out to lookout for the minimum voltage where we will see the light but there will be no lasing. The way to recognize that is to look for a sharp step or a change of light in the laser as you are lowering the voltage. will need to note down that voltage value for all three lasers. and will have to mark that as offset. so will calculate the duty cycle range for each laser. say a laser will stop lasing at 30% then then will make sure that in the calculation it starts with that value. otherwise the calculations might produce a result which might not be taking effect in the real world. I wonder if normalising the duty cycle will help in the calculation? not sure how that will be.
    • Need Voltage and current supplied by the PS but also will use the Sense pins on the PS to improve the data i'm getting.
    • PWM duty cycle, say after every increase of 1% it will report the value. this pwm cycle will be the trigger to query the data on other instruments. So say duty cycle increase from 35% to 36% then it will produce an interrupt on the python script running on windows. it will take 10 measurements of the power meter and then move to voltage and current from the power supply, take 10 measurements of that. i think thats all the measurements i need. will need to do this for the whole range of each laser. i will have to change the setup for each laser though because the setup is that way. For now will need to read up on some papers that have attempted to do the same because the reference part of the thesis looks empty right now. and i can't quote youtube videos or individual articles in it i suppose.

  • Success with controlling instruments with python

    Shoaib Mustafa08/11/2024 at 20:01 0 comments

    Happy to share that i've made some promising progress towards accessing instruments supporting usb with python. I call the project "Instrument Orchestra", Instrument Orchestra is now hosted on GitHub with its own repository. https://github.com/manhoosbilli1/Instrument_Orchestra I've provided a detailed step by step installation guide for first experiment.

    I tried about 20 packages and different softwares to access this. thought why reinvent the wheel but none worked and almost no one was using this simple approach of accessing the instrument through serial. having some experience in electronics it was easy setting it up but installing the drivers were a pain.

    My setup is going to be a sweet one with me remotely getting data from the instrument. this will allow for long lasting testing sessions even when the lab is closed. only have to have my remote laptop attached to instruments and powered on.

    Next step would be integrating all 3 instruments with this software and creating a gui with it. i think a live graph of each instruments data would be nice.

  • Thoughts on generating RGB Colors with lasers

    Shoaib Mustafa08/11/2024 at 19:59 0 comments

    I think the nearest possible application is of an rgb led and how it's able to generate a certain a color. Since i'm using a laser it will be a bit different but i think the conversion factor can be changed. I'll look into the construction of a laser.. how it's driven and find some papers that have attempted to control color of a laser.

    Side note: Just figured out why the IR wavelength was showing in the green laser. turns out the pure green lasers are rare and what we get is an IR laser lasing at 1056nm there about. The frequency is then double within the structure which halves the wavelength so we get around 532nm there about green light.

    The green laser is usually made of inGan material. but since my diode is an IR one not so sure what it's made of. Here's a proper true green laser. https://ams-osram.com/products/lasers/color-lasers-eel/osram-metal-can-to56-plt5-520b i found a good paper explaining the effects of PWM with this laser. i'll read it see if it will give me some insight into having proper pwm control with the laser.

    Interesting facts gathered from this paper.

    • the current and output power shows almost a linear trend with green laser. but no so much with blue laser.. when i'm looking into blue laser i'll have to keep that in mind.
    • Higher temperature requires more current and outputs less power.
    • Power and duty cycle graph shows best possible results with highest power, lowest current, temperature controlled at 10khz at 30C.

    i'll collect each lasers wavelength using spectrometer for CIE coordinates gamut. i'll also measure each lasers optical power with change in voltage/pwm.

    I've found that most instruments have usbtcm connection which will let us talk to the device and gather data programatically. i'll try to set that up because when the new lasers arrive i have to be able to get the data fast. even right now i have to measure, wavelength, voltage, current, pwm value, intensity and so on.. will be hard to get 1024 (10bit) data

View all 14 project logs

Enjoy this project?

Share

Discussions

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates