PDA

View Full Version : Unexplained problems



JBWolf
10-13-2011, 09:18 AM
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)


DAT
HStep byte %1001, %1000, %1100, %0100, %0110, %0010, %0011, %0001 ' Half Step Phases
Next 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, 999
And 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, 999
Goals:
#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!
(http://forums.parallax.com/member.php?41345-Beau-Schwabe-%28Parallax%29)

Snaily
10-13-2011, 01:28 PM
Wow, nice work...

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

prof_braino
10-13-2011, 04:49 PM
A shorter pulse would make the vibration and wobble less visible, allow a shorter time between dots.
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.

Peter Jakacki
10-13-2011, 05:02 PM
Stepper motors essentially clunk to a halt when they detent in their step position. Those helices look a lot like the poor laser is vibrating around when this happens. As has been suggested try giving it a rest before firing even if it's too slow. This is just so you can determine the cause. The suggestion to fire on the fly is sound but to dampen the vibrations you might have to have a look at microstepping the motor smoothly without having to really stop at all. I've been playing with the L6470 3A microstepper and it's a really nice and simple chip to use.

JBWolf
10-14-2011, 01:08 AM
I will add a small delay after movements to see if this resolves the helix problem.... but this also creates another problem, now the frame will take even longer to draw.... so it will be 1 frame per second after adding delays?
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

Heater.
10-14-2011, 01:32 PM
Any ideas on how to compare a current position against all data in an array near instantaneously

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.

frank freedman
10-14-2011, 02:44 PM
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

jrjr.
10-15-2011, 05:56 AM
JBWolf,

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

JBWolf
10-15-2011, 11:35 AM
Yes I use "galvos" probably too often as a general term.
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.

JBWolf
10-15-2011, 11:37 AM
I do have a few more Q's though hehe
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.

JBWolf
10-15-2011, 11:51 AM
Heater... I removed all unnecessary delay commands, the laser delay and a delay of 1700 per step (for returning from the bottom of the frame to the top) are the only ones remaining.
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.


PUB FrameProcessor(FrameX) | ID, Xsize, Ysize, LSRDelay, FRMrpt, Xtmp, Ytmp, Counter1, Counter2, CounterX, FrameCount, Enable, ON, OFF, CR

ID := Long[FrameX][0]
Xsize := Long[FrameX][1]
Ysize := Long[FrameX][2]
FrameCount := Long[FrameX][3]
FRMrpt := Long[FrameX][4]
LSRdelay := 1000
Xpos := 0
Ypos := 0
Xtmp := 0
Ytmp := 0
Counter1 := 0
Counter2 := 0
CounterX := 0
Enable := 0
OFF := 0
ON := 1
CR := 0

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 := Long[FrameX][Counter1] ' Read X data
Counter1 := Counter1 + 1 ' Move array counter +1
Ytmp := Long[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 Ypos == Ysize ' If finished drawing frame
if CR == 0 and Xpos == Xsize ' If moving Right, last Xpos is 12
QUIT
if CR == 1 and xpos == 1 ' If moving Left, last Xpos is 1
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 Ypos == Ysize ' If finished drawing frame
if CR == 0 and Xpos == Xsize ' If moving Right, last Xpos is 12
QUIT
if CR == 1 and xpos == 1 ' If moving Left, last Xpos is 1
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

DAT

HStep byte %1001, %1000, %1100, %0100, %0110, %0010, %0011, %0001
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
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.

JBWolf
10-15-2011, 12:05 PM
One thing I just thought about.... writing an interpreter.
It would read the data holding the frame 'pixels', and determine the best way to hit all pixels without wasted movements.

JBWolf
10-15-2011, 12:35 PM
aha, it is that data array thats slowing it down so much.
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!

JBWolf
10-15-2011, 03:21 PM
I just finished tidying up the code better.... things like x = x + 1 are now ++x and so on.
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?

JBWolf
10-15-2011, 03:26 PM
This is as far as I could simplify it.
Any ideas on how to reduce the loop times?



PUB FrameProcessor(FrameX) | LSRDelay, Counter1, Counter2, CounterX, CR

LSRdelay := 200
Counter1 := 0
Counter2 := 0
CounterX := 0
CR := 0

Xpos := Long[FrameX][1] / 2 ' Mark X center position in relation to max frame size
Ypos := Long[FrameX][2] / 2 ' Mark Y center position in relation to max frame size

'------------------------------------------------ Start Processing --------------------------------------------

repeat Long[FrameX][4] ' 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 ' Increment Y step counter
if stpy < 0 ' 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 // 8
outa[12..15] := HStep[stpx]
waitcnt(clkfreq / 1700 + cnt)
Xpos := --Xpos


'--------------------------------------------------== Draw Frame ==---------------------------------------
Counter1 := 0 ' Clear all counters
Counter2 := 0
CounterX := 0
CR := 0

repeat Long[FrameX][2] ' Repeat all Y lines
repeat Long[FrameX][1] ' Repeat all X lines
CounterX := ++CounterX ' 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 ' Roll through array
Counter2 := ++Counter2 ' Track loop counter through data sets
if Long[FrameX][Counter1] == Xpos and Long[FrameX][Counter1 + 1] == Ypos ' Check for position match
waitcnt(clkfreq / (LSRDelay * 2) + cnt)
outa[LaserPin]~ ' Laser ON
waitcnt(clkfreq / LSRDelay + cnt) ' Laser time on delay
outa[LaserPin]~~ ' Laser OFF
QUIT ' Exit repeat loop
elseif Counter2 == Long[FrameX][3] ' If all data pairs checked without match
QUIT ' Exit repeat loop
Counter1 := Counter1 + 2

if Ypos == Long[FrameX][2] ' If finished drawing frame
if CR == 0 and Xpos == Long[FrameX][1]' If moving Right, last Xpos is 12
QUIT
elseif CR == 1 and Xpos == 1 ' If moving Left, last Xpos is 1
QUIT


if CounterX == Long[FrameX][1] ' If all pixels in line covered
stpy := ++stpy // 8 ' Step Y down 1
outa[8..11] := HStep[stpy]
waitcnt(clkfreq / 1700 + cnt) ' Minimum Delay
Ypos := ++Ypos ' Mark new Y position
CounterX := 0 ' Reset X pixel line counter
CR := ++CR // 2 ' Mark carriage return direction
QUIT ' Exit this X line loop to avoid stepping out of bounds

if CR == 1 ' If at Right side, move Left
stpx := ++stpx // 8
outa[12..15] := HStep[stpx] ' send phase pulse
waitcnt(clkfreq / 1700 + cnt) ' set speed, max speed = H1800 F800 W700
Xpos := --Xpos ' write counter to track new position
elseif CR == 0 ' If at Left side, move Right
stpx := --stpx
if stpx == -1
stpx := 7
outa[12..15] := HStep[stpx] ' send phase pulse
waitcnt(clkfreq / 1700 + cnt) ' set speed, max speed = H1800 F800 W700
Xpos := ++Xpos ' write counter to track new position


if Ypos == Long[FrameX][2] ' If finished drawing frame
if CR == 0 and Xpos == Long[FrameX][1] ' If moving Right, last Xpos is 12 **Problem** Xpos == Xsize before pixel is written**
QUIT

if CR == 1 and Xpos == 1 ' If moving Left, last Xpos is 1 **Problem** Xpos == 1 before pixel is written**
QUIT



'---------------------------------- Frame drawing complete - Return to center --------------------------------

repeat until Ypos == (Long[FrameX][2] / 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 > (Long[FrameX][1] / 2)
repeat until Xpos == (Long[FrameX][1] / 2) ' Move X from current position to center by moving left
stpx := ++stpx // 8
outa[12..15] := HStep[stpx]
waitcnt(clkfreq / 1700 + cnt)
Xpos := --Xpos

elseif Xpos < (Long[FrameX][1] / 2)

repeat until Xpos == (Long[FrameX][1] / 2) ' Move X from current position to center by moving right
stpx := --stpx
if stpx == -1
stpx := 7
outa[12..15] := HStep[stpx]
waitcnt(clkfreq / 1700 + cnt)
Xpos := ++Xpos
'---------------------========================= END PROCESSOR ===================-----------------------------

frank freedman
10-15-2011, 04:20 PM
What make and model are the steppers. As to the thought of multiple cogs, consider:
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

frank freedman
10-15-2011, 04:24 PM
This is as far as I could simplify it.
Any ideas on how to reduce the loop times?



PUB FrameProcessor(FrameX) | LSRDelay, Counter1, Counter2, CounterX, CR

LSRdelay := 200
Counter1 := 0
Counter2 := 0
CounterX := 0
CR := 0

Xpos := Long[FrameX][1] / 2 ' Mark X center position in relation to max frame size
Ypos := Long[FrameX][2] / 2 ' Mark Y center position in relation to max frame size

'------------------------------------------------ Start Processing --------------------------------------------

repeat Long[FrameX][4] ' 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 ' Increment Y step counter
if stpy < 0 ' 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 // 8
outa[12..15] := HStep[stpx]
waitcnt(clkfreq / 1700 + cnt)
Xpos := --Xpos


'--------------------------------------------------== Draw Frame ==---------------------------------------
Counter1 := 0 ' Clear all counters
Counter2 := 0
CounterX := 0
CR := 0

repeat Long[FrameX][2] ' Repeat all Y lines
repeat Long[FrameX][1] ' Repeat all X lines
CounterX := ++CounterX ' 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 ' Roll through array
Counter2 := ++Counter2 ' Track loop counter through data sets
if Long[FrameX][Counter1] == Xpos and Long[FrameX][Counter1 + 1] == Ypos ' Check for position match
waitcnt(clkfreq / (LSRDelay * 2) + cnt)
outa[LaserPin]~ ' Laser ON
waitcnt(clkfreq / LSRDelay + cnt) ' Laser time on delay
outa[LaserPin]~~ ' Laser OFF
QUIT ' Exit repeat loop
elseif Counter2 == Long[FrameX][3] ' If all data pairs checked without match
QUIT ' Exit repeat loop
Counter1 := Counter1 + 2

if Ypos == Long[FrameX][2] ' If finished drawing frame
if CR == 0 and Xpos == Long[FrameX][1]' If moving Right, last Xpos is 12
QUIT
elseif CR == 1 and Xpos == 1 ' If moving Left, last Xpos is 1
QUIT


if CounterX == Long[FrameX][1] ' If all pixels in line covered
stpy := ++stpy // 8 ' Step Y down 1
outa[8..11] := HStep[stpy]
waitcnt(clkfreq / 1700 + cnt) ' Minimum Delay
Ypos := ++Ypos ' Mark new Y position
CounterX := 0 ' Reset X pixel line counter
CR := ++CR // 2 ' Mark carriage return direction
QUIT ' Exit this X line loop to avoid stepping out of bounds

if CR == 1 ' If at Right side, move Left
stpx := ++stpx // 8
outa[12..15] := HStep[stpx] ' send phase pulse
waitcnt(clkfreq / 1700 + cnt) ' set speed, max speed = H1800 F800 W700
Xpos := --Xpos ' write counter to track new position
elseif CR == 0 ' If at Left side, move Right
stpx := --stpx
if stpx == -1
stpx := 7
outa[12..15] := HStep[stpx] ' send phase pulse
waitcnt(clkfreq / 1700 + cnt) ' set speed, max speed = H1800 F800 W700
Xpos := ++Xpos ' write counter to track new position


if Ypos == Long[FrameX][2] ' If finished drawing frame
if CR == 0 and Xpos == Long[FrameX][1] ' If moving Right, last Xpos is 12 **Problem** Xpos == Xsize before pixel is written**
QUIT

if CR == 1 and Xpos == 1 ' If moving Left, last Xpos is 1 **Problem** Xpos == 1 before pixel is written**
QUIT



'---------------------------------- Frame drawing complete - Return to center --------------------------------

repeat until Ypos == (Long[FrameX][2] / 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 > (Long[FrameX][1] / 2)
repeat until Xpos == (Long[FrameX][1] / 2) ' Move X from current position to center by moving left
stpx := ++stpx // 8
outa[12..15] := HStep[stpx]
waitcnt(clkfreq / 1700 + cnt)
Xpos := --Xpos

elseif Xpos < (Long[FrameX][1] / 2)

repeat until Xpos == (Long[FrameX][1] / 2) ' Move X from current position to center by moving right
stpx := --stpx
if stpx == -1
stpx := 7
outa[12..15] := HStep[stpx]
waitcnt(clkfreq / 1700 + cnt)
Xpos := ++Xpos
'---------------------========================= END PROCESSOR ===================-----------------------------


PASM
Catalina C

Frank

JBWolf
10-16-2011, 04:51 PM
I know absolutely nothing about ASM, seems like a big undertaking to learn it.
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.

frank freedman
10-16-2011, 06:55 PM
I know absolutely nothing about ASM, seems like a big undertaking to learn it.
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





'----------------------------------------------
' This is a demonstration of using shared variables
' between SPIN and PASM.
'
con
_clkmode = xtal1 + pll16x
_clkfreq = 80_000_000

obj
fdx : "FullDuplexSerial" ' include fdx object for terminal

var
long command ' this is the command variable
long share[4] ' these are shared variables

pub start | n

fdx.start(31,30,0,115200) ' start serial port
cognew(@pasm, @command) ' start pasm demo
waitcnt(clkfreq+cnt) ' wait for fdx and pasm start

repeat

command := -1 ' send non-zero as the "go" command
repeat while command ' wait until the command is done

fdx.tx($a) ' print a newline
fdx.tx($d)
fdx.str(string("shared values:"))

repeat n from 0 to 3 ' print the values
fdx.tx(" ")
fdx.hex(share[n],8)

waitcnt(clkfreq+cnt) ' don't print too fast


'----------------------------------------------
' this code increments shared array variables
' every time command is non-zero
'
dat org 0
pasm
mov tmp, par ' par is used as the command pointer

add tmp, #4 ' shared array starts 4 bytes after command address
mov ptr1, tmp ' save shared[0] address
add tmp, #4 ' next address
mov ptr2, tmp ' save shared[1] address
add tmp, #4 ' next address
mov ptr3, tmp ' save shared[2] address
add tmp, #4 ' next address
mov ptr4, tmp ' save shared[3] address
mov tmp, #0

:loop
rdlong cmd, par ' wait for user command
tjz cmd, #:loop ' if no command, jump to #:loop

rdlong dat1, ptr1 ' read shared data
rdlong dat2, ptr2
rdlong dat3, ptr3
rdlong dat4, ptr4

add dat1, #1 ' increment data
add dat2, #1
add dat3, #1
add dat4, #1

wrlong dat1, ptr1 ' write shared data
wrlong dat2, ptr2
wrlong dat3, ptr3
wrlong dat4, ptr4

wrlong tmp, par ' let user know we're done
jmp #:loop


cmd res 1 ' the command register

dat1 res 1 ' data temporary registers
dat2 res 1
dat3 res 1
dat4 res 1

ptr1 res 1 ' pointers to shared array
ptr2 res 1
ptr3 res 1
ptr4 res 1

tmp res 1 ' temporary pointer

fit $1ef ' don't let PASM grow beyond $1ef

'
' end of file
'----------------------------------------------

kbash
10-17-2011, 07:34 AM
JBWolf,

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.

frank freedman
10-17-2011, 08:08 AM
JBWolf,

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.

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

JBWolf
10-17-2011, 03:45 PM
Wow I've never seen an acousto-optic deflector, sounds interesting (and very expensive)
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?

photomankc
10-17-2011, 04:32 PM
It's easier to do with a step/dir driver. Something like Sparkfun sells as the Big Easy Driver will make it loads easier to accomplish. Micro stepping involves setting up in-between levels of current in the coils with PWM. A micro can do it of coarse but it's a good bit of work to setup. On a driver you just set the config for whatever micro stepping level you want that it supports and send step pulses to the drive and the motor goes where you want. Steppers at full-step are noisy, growling, clunky things. By the time I go down to even 1/4 step microstepping the motors are MUCH smoother moving. It does mean that that you have to then generate step pulse that many times faster to keep up the same rate of speed.

Peter Jakacki
10-17-2011, 04:42 PM
If you can use bipolar motors then an easy to use chip that will do 128 step (smooth as) microstepping is the L6470 (http://www.st.com/internet/analog/product/248592.jsp) in a 28-pin power HTSSOP. If you are interested I will have some small modules soon and they are very easy to drive, in fact they practically do everything including stall detection etc. I am driving a rather large and heavy 1.5kg 5A motor with this chip and it's performing very nicely so I am sure you will not have any problems with this approach.

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.

photomankc
10-17-2011, 07:12 PM
Well heck! Whats left for the micro to do then!




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.