Unexplained problems
JBWolf
Posts: 405
Ok so first step was to make a unipolar stepper move in any direction with outa[4pins]~~
This was completed and works great, the phase steps are listed below and works perfectly for using 2 stepper motors to move in an up/down left/right fashion. I can get them both to move to any specific point in any direction, and hold that position for any specific amount of time before moving to the next. These positional movements seem to be very accurate without wavering motions in 'repeat' loops with a delay no less than waitcnt(clkfreq / 1800 + cnt)
This also works great using a custom laser driver... I find any delay of 100ms or less provides a perfectly visible pulse.
So now to combine the two.
Goal: Pre-define a "frame" to be drawn with the laser combined with motor movement
The general idea would be as simple as possible, define a grid and move through it turning on the laser as defined in the 'frame' variable. The frame variable defines the grid size, laser pulse time and amount of times to repeat each frame... plus the data that specifies which points to turn on the laser.
Details:
The program reads in the data from the 'frame' variable..... which pre-defines the amount of pixels/steps on the X and Y axis.
It then moves through the grid by starting at the top left (pixels 1x1), moves right until the max X grid size reached, steps down one to the new Y line, then goes back through the X line until max X grid size reached, steps down one to the new Y line... and repeats until all X & Y lines are completed.
It then repeats that 'frame' the amount of times specified in the 'Frame' variable.
This works using the code below, But... First of all this takes much too long between individual pixel movements.
I suspect this is because it rolls through the entire array of frame data to compare the current position against a match in the Frame data.
So in structuring the 'Frame' data, you can define pixels to turn on, anywhere in the data as it checks each 'current position' against all data in the 'frame' variable.
So to draw a 12x12 frame, it takes about 1/2 sec per frame.... this is super slow (2 frames per sec) and must be sped up by at least 5x
Next problem is:
I am not getting a single pixel, Instead I am getting a helix in certain spots, horizontal lines in others.
During initial testing, I was using long delay times... but I was able to move the motor to a point and pulse the laser. This gave a perfect display of a tiny laser dot on the wall at that point.
I cannot explain any of these problems ... if there are 80 million cycles per second, why is it taking 40 million to draw a single frame?
If the coding tells the motor to step right just one movement, why am I getting a helix?
I have isolated the platform that the laser & motors are mounted on, it cannot move/wobble. So I know for sure it is the motors causing this odd movement result.
The first attached picture is of the 'Frame' variable which is a 12x12 grid, data represents an X to be drawn from the four corners of the grid.
The second attached picture is of the 'Frame2' variable which is a 6x6 grid, data also represents an X to be drawn from the four corners of the grid.
For the pictures, I had to use a long exposure to capture all 'pixels' in the frame... the first picture (12x12 grid) is a double exposure, so you are actually seeing 2 frames drawn while the camera moves down and right a lil
Here is the frame data for both:
You might notice delays of 4000 & 2000 in the 'draw frame' area of the program.... this is when I realized that it didn't matter what delay I used because the rest of the program took too long to execute.
You can see how these were eventually removed from the program with a remark char ( ' )... this made no visible difference in the draw speed
#1 Speed up each frame to a minimum of 10 per second
#2 Make pixels a single 'dot', not helix's and horizontal lines
PS - Accomplishing this task was the sole motivator behind purchasing and learning how to use the propeller.
I am still new to the prop and have tons to learn, I am not asking for someone to do my work, rather someone to guide my next step... I am kind of stuck at this point.
I need to figure out how to utilize the other processors to speed up this program, or how to re-write the program more efficiently to meet all goals.
I realize the motor problem with the helix movements may be conditional to my particular steppers... which is why I will address this last
I sincerely appreciate any help
And credits to those who have already helped with this project (Beau Schwabe, kuroneko, Mike Green, cluso99, MindRobots) , Thank you!
This was completed and works great, the phase steps are listed below and works perfectly for using 2 stepper motors to move in an up/down left/right fashion. I can get them both to move to any specific point in any direction, and hold that position for any specific amount of time before moving to the next. These positional movements seem to be very accurate without wavering motions in 'repeat' loops with a delay no less than waitcnt(clkfreq / 1800 + cnt)
DAT HStep byte %1001, %1000, %1100, %0100, %0110, %0010, %0011, %0001 ' Half Step PhasesNext was to get a laser to turn on and off with a simple outa[laserpin]~~
This also works great using a custom laser driver... I find any delay of 100ms or less provides a perfectly visible pulse.
So now to combine the two.
Goal: Pre-define a "frame" to be drawn with the laser combined with motor movement
The general idea would be as simple as possible, define a grid and move through it turning on the laser as defined in the 'frame' variable. The frame variable defines the grid size, laser pulse time and amount of times to repeat each frame... plus the data that specifies which points to turn on the laser.
Details:
Frame DAT Structuring Format: ID# = Frame ID starting at 0 for easy reference, no limit Xsize = # of pixels on Xaxis, max = 20 Pixel spacing = .9deg Ysize = # of pixels on Yaxis max = 20 LSR Dly = Laser Delay, Minimum speed = 100 FRM RPT = Amount of times to repeat a single frame END = A value of 999 is the terminator to mark end of frame data. Must direclty follow last pixel data. ┌───────┬───────┬───────┬───────┬───────┬───────┬───────┬───────┬───────┬....→ ┬──────────┐ Frame Long │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │....→ │ END Frame│ │ ID# │ Xsize │ Ysize │LSR Dly│FRM Rpt│ Xdata │ Ydata │ Xdata │ Ydata │....→ │ 999 │ └───────┴───────┴───────┴───────┴───────┴ Pixel 1 ┴ Pixel 2 ┘ └──────────┘I got this to work with only 1 cog.
The program reads in the data from the 'frame' variable..... which pre-defines the amount of pixels/steps on the X and Y axis.
It then moves through the grid by starting at the top left (pixels 1x1), moves right until the max X grid size reached, steps down one to the new Y line, then goes back through the X line until max X grid size reached, steps down one to the new Y line... and repeats until all X & Y lines are completed.
It then repeats that 'frame' the amount of times specified in the 'Frame' variable.
This works using the code below, But... First of all this takes much too long between individual pixel movements.
I suspect this is because it rolls through the entire array of frame data to compare the current position against a match in the Frame data.
So in structuring the 'Frame' data, you can define pixels to turn on, anywhere in the data as it checks each 'current position' against all data in the 'frame' variable.
So to draw a 12x12 frame, it takes about 1/2 sec per frame.... this is super slow (2 frames per sec) and must be sped up by at least 5x
Next problem is:
I am not getting a single pixel, Instead I am getting a helix in certain spots, horizontal lines in others.
During initial testing, I was using long delay times... but I was able to move the motor to a point and pulse the laser. This gave a perfect display of a tiny laser dot on the wall at that point.
I cannot explain any of these problems ... if there are 80 million cycles per second, why is it taking 40 million to draw a single frame?
If the coding tells the motor to step right just one movement, why am I getting a helix?
I have isolated the platform that the laser & motors are mounted on, it cannot move/wobble. So I know for sure it is the motors causing this odd movement result.
The first attached picture is of the 'Frame' variable which is a 12x12 grid, data represents an X to be drawn from the four corners of the grid.
The second attached picture is of the 'Frame2' variable which is a 6x6 grid, data also represents an X to be drawn from the four corners of the grid.
For the pictures, I had to use a long exposure to capture all 'pixels' in the frame... the first picture (12x12 grid) is a double exposure, so you are actually seeing 2 frames drawn while the camera moves down and right a lil
Here is the frame data for both:
Frame Long 0, 12, 12, 100, 1000, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 1, 12, 2, 11, 3, 10, 4, 9, 5, 8, 6, 7, 7, 6, 8, 5, 9, 4, 10, 3, 11, 2, 12, 1, 999 Frame2 Long 1, 6, 6, 100, 1000, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 1, 6, 2, 5, 3, 4, 4, 3, 5, 2, 6, 1, 999And here is the whole program:
You might notice delays of 4000 & 2000 in the 'draw frame' area of the program.... this is when I realized that it didn't matter what delay I used because the rest of the program took too long to execute.
You can see how these were eventually removed from the program with a remark char ( ' )... this made no visible difference in the draw speed
{{ TV Style Dual stepper cog control for ULN 2003/2803 & galvo motor 1 = pins 8-11 = Y Axis - DirY 1 = Down, 2 = Up motor 2 = pins 12-15 = X Axis - DirX 1 = Left, 2 = Right (bottom motor) Full Step & Wave = 1 revolution = 200 steps @ 1.8deg per step Half Step = 1 revolution = 400 steps @ .9deg per step Frame Processor set @ Half Step Half Step Max Speed = 1800 Full Step Max Speed = 800 Weak Step Max Speed = 700 12step +/- max clearance from home position (true center) = 22deg max frame size. ************************************************************** Frame DAT Structuring Format: ID# = Frame ID starting at 0 for easy reference, no limit Xsize = # of pixels on Xaxis, max = 20 Pixel spacing = .9deg Ysize = # of pixels on Yaxis max = 20 LSR Dly = Laser Delay, Minimum speed = 100 FRM RPT = Amount of times to repeat a single frame END = A value of 999 is the terminator to mark end of frame data. Must directly follow last pixel data. ┌───────┬───────┬───────┬───────┬───────┬───────┬───────┬───────┬───────┬....→ ┬──────────┐ Frame Long │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │....→ │ END Frame│ │ ID# │ Xsize │ Ysize │LSR Dly│FRM Rpt│ Xdata │ Ydata │ Xdata │ Ydata │....→ │ 999 │ └───────┴───────┴───────┴───────┴───────┴ Pixel 1 ┴ Pixel 2 ┘ └──────────┘ TO DO = Do even X & Ysizes only work? Launch Laser driver in new cog? using percentage value for frame delay translation out of max 1700ms delay ((1700 * Frame[3]) / 100) = new delay }} CON _clkmode = xtal1 + pll16x ' System clock → 80 MHz _xinfreq = 5_000_000 TX_PIN = 2 ' LCD Pin ID BAUD = 19_200 ' LCD Baud LaserPin = 16 OBJ LCD : "FullDuplexSerial.spin" ' LCD Object VAR long stack[2000] ' Cog stack space byte cog[2] ' Cog ID long up long right long down long left ' Directional variables long stpx, stpy long Xpos, Ypos PUB Main | Success stpx := 0 ' Phase & position counters, DO NOT RESET stpy := 0 Xpos := 0 Ypos := 0 InitVars InitPins InitLCD Calibrate '*********************$$$$$$$$$$$$$$$$$$$$$$ START MOVEMENT CALLS $$$$$$$$$$$$$$$$$$$$$$$********* cls waitcnt(clkfreq / 2 + cnt) LCD.str(string("Movement Routines")) Waitcnt(clkfreq + cnt) Test1 '*********************$$$$$$$$$$$$$$$$$$$$$$ END MOVEMENT CALLS $$$$$$$$$$$$$$$$$$$$$$$$******** ' StartFramePX ' Launches into new cog Shutdown ' StopFramePX '**********%%%%%%%%%%%%%%%%%%%% START MOVEMENT ROUTINES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%***** PUB Test1 initvars FrameProcessor '********%%%%%%%%%%%%%%%%%%%%%%% END MOVEMENT ROUTINES %%%%%%%%%%%%%%%%%%%%%%%%%%%%************* '******************************* Start Galvo Controls ************************************* PUB Shutdown cls waitcnt(clkfreq / 2 + cnt) LCD.tx(153) ' move to position 2 x 5 LCD.str(string("END")) Waitcnt(clkfreq * 3 + cnt) PUB initvars up := 2 ' initialize variables right := 2 down := 1 left := 1 PUB InitPins dira[8..11]~~ ' Yaxis Motor dira[12..15]~~ ' Xaxis Motor dira[16]~~ ' Laser output outa[16]~~ ' Laser OFF PUB Calibrate | stp stp := 0 repeat 65 outa[12..15] := WStep[stp] outa[8..11] := WStep[stp] waitcnt((clkfreq / 200) + cnt) stp := stp + 1 if stp == 4 stp := 0 repeat 24 outa[12..15] := WStep[stp] outa[8..11] := WStep[stp] waitcnt((clkfreq / 200) + cnt) stp := stp - 1 if stp == -1 stp := 3 stpx := (stp * 2) + 1 ' switch to hstep mode and initialize X stpy := (stp * 2) + 1 ' switch to hstep mode and initialize Y Waitcnt(clkfreq * 2 + cnt) ' 2 sec delay after calibrate PUB StartFramePX | success success := LaunchCOG if success == 0 ' initialize outputs and start motors in cogs LCD.str(string("FramePX Started on:" )) ' show if initialize was completed or not NewLine LCD.str(string("Cog#:")) LCD.dec(cog[1]) else LCD.str(string("Failure" )) waitcnt(clkfreq * 3 + cnt) PUB LaunchCOG : success 'cog[1] := cognew(FrameProcessor(@frame), @stack[1000]) ' Start Frame Processor PUB StopFramePX cogstop(cog[1]) ' Stop Frame Processor ' -------------------================ START MAIN CONTROL =================--------------------------- PUB Laser(state) if state == 1 outa[LaserPin]~ if state == 0 outa[LaserPin]~~ PUB FrameProcessor | ID, Xsize, Ysize, LSRDelay, FRMrpt, Xtmp, Ytmp, FrameX[450], Counter1, Counter2, CounterX, FrameCount, Enable, ON, OFF, CR FrameX[450] := 0 FrameCount := 0 LSRdelay := 0 FRMrpt := 0 Xsize := 0 Ysize := 0 Xpos := 0 Ypos := 0 Xtmp := 0 Ytmp := 0 ID := 0 Counter1 := 0 Counter2 := 0 CounterX := 0 Enable := 0 OFF := 0 ON := 1 CR := 0 '---------------------------------------------- Read in Frame data -------------------------------------------- repeat until FrameX[Counter1] == 999 ' -= FRAME DATA PARSING =- FrameX[Counter1] := Long[@Frame][Counter1] ' Read in array if FrameX[counter1] == 999 ' Check for END marker FrameCount := ((Counter1 - 4) / 2) ' Strip header & halve count- Count data pairs only else ' If no END marker Counter1 := Counter1 + 1 ' Increment Counter FrameX[Counter1] := 0 ' Initialize new Frame variable ID := FrameX[0] ' Read Frame ID # Xsize := FrameX[1] ' Read Xsize Ysize := FrameX[2] ' Read Ysize LSRDelay := FrameX[3] ' Read Laser Delay FRMrpt := FrameX[4] ' Read Frame repeat count Counter1 := 0 ' Re-init Counter for use Xpos := Xsize / 2 ' Mark X center position in relation to max frame size Ypos := Ysize / 2 ' Mark Y center position in relation to max frame size '------------------------------------------------ Start Processing -------------------------------------------- repeat FRMrpt ' Amount of times to draw a single frame defined in Frame[4] ' MOVE TO 1x1 FRAME START POSITION repeat until Ypos == 1 ' move UP to frame Y start position 1 stpy := stpy - 1 ' Increment Y step counter if stpy == -1 ' If Y step counter out of bounds stpy := 7 ' Reset Y step counter to proper phase outa[8..11] := HStep[stpy] ' Send Phase step waitcnt(clkfreq / 1700 + cnt) ' Minimum delay Ypos := Ypos - 1 ' Mark new Y position If Xpos > 1 repeat until Xpos == 1 ' Move to X position 1 if not already stpx := stpx + 1 if stpx == 8 stpx := 0 outa[12..15] := HStep[stpx] waitcnt(clkfreq / 1700 + cnt) Xpos := Xpos - 1 '--------------------------------------------------== Draw Frame ==--------------------------------------- Counter1 := 0 ' Clear all counters Counter2 := 0 CounterX := 0 CR := 0 repeat Ysize ' Repeat all Y lines repeat Xsize ' Repeat all X lines CounterX := CounterX + 1 ' Start counting current X pixels for size limits Counter1 := 5 ' Set Counter to 5 for array use at Frame data start Counter2 := 0 ' Set Counter to 0 for comparing with FrameCount repeat until Enable == 1 '-Roll through array Counter2 := Counter2 + 1 ' Track loop counter through data sets Xtmp := FrameX[Counter1] ' Read X data Counter1 := Counter1 + 1 ' Move array counter +1 Ytmp := FrameX[Counter1] ' Read Y data Counter1 := Counter1 + 1 ' Move array counter +1 if Xtmp == Xpos and Ytmp == Ypos ' Check for position match Laser(ON) ' Laser ON waitcnt(clkfreq / LSRDelay + cnt) ' Laser time on delay Laser(OFF) ' Laser OFF Enable := 1 ' Exit repeat loop elseif Counter2 == FrameCount ' If all data pairs checked without match Enable := 1 ' Exit repeat loop Enable := 0 ' Reset Variables to 0 for next use Counter1 := 0 Counter2 := 0 if Xpos == Xsize and Ypos == Ysize ' If finished drawing frame QUIT if CounterX == Xsize ' If all pixels in line covered stpy := stpy + 1 ' Step Y down 1 if stpy == 8 stpy := 0 outa[8..11] := HStep[stpy] ' waitcnt(clkfreq / 4000 + cnt) ' Minimum Delay Ypos := Ypos + 1 ' Mark new Y position CounterX := 0 ' Reset X pixel line counter CR := CR + 1 ' Mark carriage return direction if CR == 2 ' 1 = Left, 0 = Right CR := 0 QUIT ' Exit this X line loop to avoid stepping out of bounds if CR == 1 ' If at Right side, move Left stpx := stpx + 1 if stpx == 8 stpx := 0 outa[12..15] := HStep[stpx] ' send phase pulse ' waitcnt(clkfreq / 4000 + cnt) ' set speed, max speed = H1800 F800 W700 Xpos := Xpos - 1 ' write counter to track new position elseif CR == 0 ' If at Left side, move Right stpx := stpx - 1 if stpx == -1 stpx := 7 outa[12..15] := HStep[stpx] ' send phase pulse ' waitcnt(clkfreq / 2000 + cnt) ' set speed, max speed = H1800 F800 W700 Xpos := Xpos + 1 ' write counter to track new position if Xpos == Xsize and Ypos == Ysize ' If finished drawing frame QUIT '---------------------------------- Frame drawing complete - Return to center -------------------------------- repeat until Ypos == (Ysize / 2) ' Move Y from current position to center, assuming frame end is at Y+ stpy := stpy - 1 if stpy == -1 stpy := 7 outa[8..11] := HStep[stpy] waitcnt(clkfreq / 1700 + cnt) Ypos := Ypos - 1 If Xpos > (Xsize / 2) repeat until Xpos == (Xsize / 2) ' Move X from current position to center by moving left stpx := stpx + 1 if stpx == 8 stpx := 0 outa[12..15] := HStep[stpx] waitcnt(clkfreq / 1700 + cnt) Xpos := Xpos - 1 elseif Xpos < (Xsize / 2) repeat until Xpos == (Xsize / 2) ' Move X from current position to center by moving left stpx := stpx - 1 if stpx == -1 stpx := 7 outa[12..15] := HStep[stpx] waitcnt(clkfreq / 1700 + cnt) Xpos := Xpos + 1 '---------------------========================= END PROCESSOR ===================----------------------------- '******************************* End Galvo Controls *********************************** '******************************* Start LCD Commands *********************************** PUB InitLCD LCD.start(TX_PIN, TX_PIN, %1000, 19_200) ' initialize LCD waitcnt(clkfreq / 100 + cnt) BKLon ' Turn on LCD BackLight CLS waitcnt(clkfreq / 20 + cnt) PUB Newline LCD.tx(13) pub NextLine LCD.tx(10) PUB CLS LCD.tx(12) waitcnt(clkfreq /500 + cnt) PUB Back (n) repeat n LCD.tx(8) PUB BKLon LCD.tx(17) PUB BKLoff LCD.tx(18) PUB BlinkON LCD.tx(23) PUB Default LCD.tx(24) PUB NoCursor LCD.tx(22) PUB LCDoff LCD.tx(21) '********************************* End LCD Commands *********************************** DAT HStep byte %1001, %1000, %1100, %0100, %0110, %0010, %0011, %0001 ' Half Step - best resolution FStep byte %1001, %1100, %0110, %0011 ' Full Step - max torque WStep byte %1000, %0100, %0010, %0001 ' Wave Step - weak torque Frame Long 0, 12, 12, 100, 1000, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 1, 12, 2, 11, 3, 10, 4, 9, 5, 8, 6, 7, 7, 6, 8, 5, 9, 4, 10, 3, 11, 2, 12, 1, 999 ' First Frame data Frame2 Long 1, 6, 6, 100, 1000, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 1, 6, 2, 5, 3, 4, 4, 3, 5, 2, 6, 1, 999Goals:
#1 Speed up each frame to a minimum of 10 per second
#2 Make pixels a single 'dot', not helix's and horizontal lines
PS - Accomplishing this task was the sole motivator behind purchasing and learning how to use the propeller.
I am still new to the prop and have tons to learn, I am not asking for someone to do my work, rather someone to guide my next step... I am kind of stuck at this point.
I need to figure out how to utilize the other processors to speed up this program, or how to re-write the program more efficiently to meet all goals.
I realize the motor problem with the helix movements may be conditional to my particular steppers... which is why I will address this last
I sincerely appreciate any help
And credits to those who have already helped with this project (Beau Schwabe, kuroneko, Mike Green, cluso99, MindRobots) , Thank you!
Comments
1 On the helices: could it be your mechanical system lacks stiffness, and vibrates after the steppers stop? You might consider waiting a little before you turn on the laser, or adding some mechanical dampening.
2 On the speed:
- You might try to use another method to store the frame after the 'frame data parsing'. Perhaps you could use a bitmap. Say you put every scanline in a long, with the bits representing the pixels. To determine if a pixel is on, you (only) perform an and on the current scanline long, and a mask (holding a single 1) that you shift every time you move to the next pixel. That might be faster...
- When x and y both need to move (when you return to 1,1 after a frame), you could combine these, and waitcnt only once for both steppers.
- Perhaps, when the rest of the code is fast enough, you can decrease the wait times between the
steps dynamically, once the motors start to move.
Regards Snaily
Are you firing the laser each time the motor stops? If you fire the laser while it is still moving, you might get a more consistent dot.
If execution speed is an issue, you might want to use assembler.
If execution speed is an issue AND you want to test interactively, you might want to try forth. FORTH is designed for writing drivers and testing on the fly, it might make life a LOT easier for you, at least until you have all your operational parameters nailed down.
I have to speed up this program... Any ideas on how to compare a current position against all data in an array near instantaneously?
There must be some way to use the other cogs to split up tasks
I should also mention that the laser I am using is a DPSS green with probably a cheap pump diode... I might be able to speed up the pulse time by using a completely solid state diode instead, their response times are much better.
Right now there are no delays inserted in the programming while drawing a frame, except for the delay used to create a laser pulse which is waitcnt(clkfreq / 100 + cnt).... so maybe this is my problem, in a 12x12 grid there are 144 points that must be covered, so a waitcnt of 100 would mean it takes 1.44sec to cover them all I believe.
I will try switching to a different diode and reducing pulse time to 400
That is not going to happen.
I'm have not looked into what you are doing closely but seems to me that you want to:
1) Scan a laser across a grid of 12 by 12 points.
2) Pulse the on the laser, or not, at each point thus displaying a 12 by 12 image of pixels.
So why not:
1) Move the steppers such that the laser points to top left point (0, 0)
2) Step the laser across the first (top) line in a continuous motion from left to right.
3) Pulse the laser on for each "pixel" point as you go. Probably no need to worry about stopping and resting at each point.
4) Step down a line in the Y direction.
5) Step the laser back across horizontally from righ to left and pulse when passing "pixel" points.
6) And so on repeating steps 2) to 5) six times to create 12 lines of pixels.
Now as you are doing all this the software only has to read through an array of 144 numbers, perhaps bytes containing 1 for ON and 0 for OFF, moving from one to the next as each pixel is passed by the laser. No need to do any reading or comparing to all data at the same time.
This should all go by a lot quicker than once per half second quite easily.
Looks like heater is suggesting an continuous x/y scan from an array of bits. If the mirrors know where they are, then the position could select pixel bits in a word sequentially as X scans, and then select the line word based on the Y position. There is just one more spanner to toss into theworks so to speak. Linearity. For a small row/column count, short distance source to target, not to noticeable. But if the distances increase, either by more pixel/lines or source to target distance gets large, then for a given constant scan speed the distance between pixels will decrease as the scan approaches center and increase as the beam moves away from the center point. It will happen on both the x and y axis.
Frank
It looks like a mirror mass problem, causing overshoot.
Consider 'slugging' one of the mirrors with extra mass and see if it gets worse.
You used the term 'galvos' in the program,but you are using steppers,
that's a <world> of difference in quality and accuracy. I'm sure you know that.
If you can, please show pics of the mechanical configuration as well.
jr
I tried reducing the delay to 1000 and still is taking way too much time to draw a single frame.
I might just have to either make my own true galvos, or find a cheap supplier of them.
I think these stepper motors are too slow with too large of a step for any kind of decent resolution and frame rates. Think I'm going to temporarily go back to drawing with direct movements rather than pixels, and start learning more about closed loop servos. Anyone knowledgeable in this area by chance?
This sure has been an excellent learning adventure though... I feel like I have a handle on the basics now and can identify most common problems in my code.
I'm wondering about dividing up tasks to speed up program times by launching more cogs.
I am stuck right now trying to figure out the fastest way to do this... first off, most the time I do not have a static task to perform, I need the cog to 'stay alive' so that it basically sits idle until I change a variable or make a call.
I have gotten a cog to work independently by putting it in an endless repeat loop... but sometimes I run into timing issues with this.
What is the best way to launch a new cog AND control it from the main cog? Not just pass data 1 time during launch.
The test frame I am drawing is an X, it starts at 'pixel' 1x1 which is the top left corner, and ends at pixel 1x12 which is the bottom left corner.
The exact amount of pixels drawn are 12, so laser delays are 12 x 100.
Thats it... the rest of the time is spent somewhere else. I am getting at absolute best with the 12x12 size is 2 frames per second.
I have since done a revision and removed one of the data arrays, it sped up a lil bit but nowhere near enough. I just tested with a laser delay of 1000.... almost exactly the same speed if not the exact same speed.
What is going on here? It should only be repeating the code in the "draw frame" area... and the only thing in there I cannot tell how long it is taking is the repeat array to check the current position, against positions listed as 'pixels' in the frame DAT array.
It would read the data holding the frame 'pixels', and determine the best way to hit all pixels without wasted movements.
I replaced this:
Xtmp := Long[FrameX][Counter1] ' Read X data
Counter1 := Counter1 + 1 ' Move array counter +1
Ytmp := Long[FrameX][Counter1] ' Read Y data
Counter1 := Counter1 + 1
if Xtmp == Xpos and Ytmp == Ypos
With this:
if Long[FrameX][Counter1] == Xpos and Long[FrameX][Counter1 + 1] == Ypos
Counter1 := Counter1 + 2
I am now getting 5 frames per second.
Lets see If I can reduce this some more and get it working like I had hoped!
This did improve speed, I maybe get an extra frame per second, but its still nowhere near fast enough.
Lets say I need to access Array[3] a whole bunch of times in a loop...
Is it faster to read that value with a command pointing directly to it?
i.e.
repeat
IF long[array][3] <> X
less code here using X...
OR, would it be faster like this...
Y := long[array][3]
repeat
IF X <> Y
more code here using X
Seems to me that it would be better to point to it directly?
Otherwise I have to create a local variable for storing the value... is there a difference in access times for local variables?
Any ideas on how to reduce the loop times?
Use a cog each for x and y scan. Use a cog to read out the image array to the laser based on the x and y position of the laser. Use two shared ram locations updated by the step cogs after each step. Leave the stepper cogs running continuously. Keep the readout laser cog repeating continuously. Put into all these cogs a pause command via shared hub location. A master cog can pause the whole works.
As an alternate to shared memory positions, use separate cogs for x and y, and pulse an i/o pin each and have the laser control cogs two counters count these to keep track of the position. Then have a longer pulse out that the laser hub could see as a sync pulse from the stepper hubs to reset the counters. Having an identifiable sync time could enable the master to load new frames between scans.
Frank
PASM
Catalina C
Frank
I'll have to think about how to structure extra cogs... what do you mean by a shared hub?
I think I understand what you mean by shared memory locations, I was trying this earlier by launching a new cog with an IF statement inside an endless repeat loop to see if the shared variable had changed... it would then execute inside the IF statement.
It would be nice if I could define a PUB to only run inside a new cog, then whenever that PUB is called, it would automatically run inside that new cog.... rather than having to launch every single time with a 'cognew', or keeping it alive with an endless repeat.
Jb,
The code below was posted by jazzed in the PASM for beginers thread. If you followed it at all, you probably noticed many excellent contributions by jazzed, stephen, potatohead, kuroneko and many others. The code jazzed posted I have copied here for your enjoyment shows clearly a couple of things. First, the question of shared hub (should have had the word memory after it) is nicely shown with the passing of a control word to a process running in a cog to start and stop it. In this case sending a non-zero value will cause it to execute. Here a -1 is passed. If you set up known locations in the hub memory, you can then tell the cogs where to find at least the first address of a block of data in hub ram via PAR register in the cog. Once that is known, the cog can read the rest of the data block for parameters, addresses, or whatever you define the values to be.
If you created a laser control function to run in a separate cog, you could pass it the start address of a say 20 longs array with the 20 lines of frame data. Then tracking the x position you could read out the individual bits of the line to illuminate each pixel point.
Tracking the mirror position could have the x and y cogs write their position post move into shared locations that the laser control could read for addressing into the frame line array and current pixel location. This would be a sort of absolute address of the position as opposed to the earlier method of using a pulse from the x or y cog post move and having the laser cog keep track of these and building a current location from the counted pulses.
Frank
I have been building marking systems since the early 80's. I did the design of a laser marking system similar to the one you are making in 1986. ( I remember because the Challenger blew up one day while I was working on it. but I digress. )
From the looks of your photo, the double image indicates you are using a regular mirror to steer your beam. ( Front surface mirrors will get rid of the double image. You can get them by taking a junk scanner and pulling the optics apart. There will be two or three in there )
The spirals you are seeing are most likely from the Ringing that the steppers do naturally, the shape of the spiral is related to whether the motors are on a full or half step since they have more holding power on full steps. Microstepping will get rid of most of the ringing if you have a driver that will do it. Since you are doing simple phase stepping, you probably won't get rid of the ringing, so you WILL need to add a delay value after each movement before you trigger your laser.
Oddly enough, you may get MORE ringing by increasing the current ( or voltage ) to the motors. ( Stepper drives often allow you to cut back on the current to get better performance for your particular load ) The easiest way to dampen SOME of this ringing is to add friction to the shaft of the stepper. ( try something like a clothes pin or even an eraser secured on the motor mount. ) It makes the stepper work slightly harder, but doesn't tend to overshoot and Hunt the final position as much.
All steppers work better if you include some form of speed ramping in your positioning algorithm.
Driving full speed from position to position is like trying to drive a car with the throttle stuck open by turning the ignition on and off. (Ok...Ok... so you're not really going to hurt the steppers and likely won't kill as many innocent bystanders... but it's kind of similar)
next, your character generator... I didn't read through your code, but I wasn't sure why you would have such a complex function for generating your dots.
I have a stylus marker I run with a propeller. It does basically the same thing you want to do with the laser,but uses a carbide pin to make each dot in metal or other material. I generated simple movements for a 5x7 dot matrix character set: lf rt up dn dl dr ul ur then added position and DOT functions. Upd dnd ( up and dot, down and dot , etc ) Trying to cover all 144 positions is just a touch masochistic unless you're doing graphic output. Your X character can be done in 19 movement commands something like:
pub draw_X
rtd ' starting one dot to the left of the bottom left dot, move right, and make a dot.
Urd ' up and right one square, make a dot.
.
.
.
etc at the end, you move one space to the right and your ready to mark the next character.
Meanwhile.. back at the ranch, Steppers CAN do the job, but they will never do it well. You CAN do your development using steppers then go to DC motors ( with encoder feedback ) and get about a 10 times increase in speed using the exact same code, but they will never hit the same speed as dedicated galvos.
The fastest way to steer a laser beam is with acusto-optic deflectors. ( an ultra sonic transducer sets up stress in a piece of glass that changes the density of the glass and deflects the beam different amounts according to the frequency of the soundwave ) But these things are more for people trying to shoot things out of the sky than they are for someone trying to build a cheap laser marking system.
If you're ok just making a green dot, your fine with just mirrors, but if you want to try to MARK something someday, then it gets even more complicated... you can NOT bounce a laser beam capable of marking on metal off of a metal ( front surface ) mirror. The beam has to be expanded to a size that does not have enough density to hurt your optics. You do this with one set of lenses that expands the beam, you steer it around... then you have to RE-focus it back into a beam concentrated enough to mark, cut, etc with another set of lenses THEN you have to make sure that the focus of the beam is corrected to mark on your part ( usually done with yet another lens called a Flat Field lens. These suckers are big and you guessed it... expensive )
I was about to go on to describe a laser marker I designed that doesn't use any of this stuff, but that's sorta down the road a bit for you. For now, simplify your ideas for HOW to generate your characters. If you plan on doing something useful with it someday, add in scaling, and even consider adding rotation early in the game. What you have now is a great start. The fact that you have ANYTHING working is 90% of a design. You may STAY at 90% for quite a while... but you're way ahead of the game and will continue to learn and improve as you go.
Best of luck to you, but mainly... HAVE FUN!
(PS... DO start learning assembly. It may not be where ALL the action's at... but it's definitely where the speed is. )
Ken B.
Or scanning to lay down an image (They still do that!!! and scan plates to recover latent xray images) on film for creating a hardcopy of a medical image. As in the Siemens Digicam, probably the most expensive design of its class in the late '80s early 90s!!!! Galvos, lenses, 50lb of first surface folding mirror, HeNe into an A/O modulator painful alignment processes and interesting acoustic/mechanical artifacts................
Frank
I am of course using front surface mirrors rated well beyond the Mw output of my lasers... the double image came from a long shutter speed on the camera, I had to use a long exposure to catch all points in the frame as it was taking atleast 1/2 sec.
Yes I see how a program like yours could use a very little amount of code... but there are several unique features to mine that require more.
I cannot limit a frame to only the points being drawn right now as I am feeding it up to 100 different frames all with unique pixel locations. So I would actually have to write an interpreter to sort through the pixels used in the frame to reduce the stepper motions, which means even more code.
One way I have been thinking of getting around this is by mandating that all frames have their pixels listed in sequential order.... right now you could write the whole frame, realize you missed a pixel, throw it in last and it will still run fine.
I will definitely start on assembly sometime in the near future... right now I just have too much on my plate
The steppers I am using are el'cheapo chinese 12v 1A, Unipolar .9deg single shaft
mirrors are mounted with aluminum rod and screw, balance is good. I did not piece it together, this is an actual chinese 'galvo' or 'scanner' or whatever you would like to call it.
I am feeding it the full 1A... maybe reducing this could improve the accuracy?
I do not know how to microstep these... is this easy to do with the propeller?
BTW, you don't have to generate step clocks with this chip (only if you want to) as it has commands that handle the whole moving to the next position thing etc along with acceleration/deceleration profiles handled automatically.
I know, all the more important stuff like plotting where to go next and how fast to get there. That's a seriously neat little chip there. Having accel handleld for you in a package that handle up to that much current is pretty darn cool.