Shop OBEX P1 Docs P2 Docs Learn Events
Unexplained problems — Parallax Forums

Unexplained problems

JBWolfJBWolf Posts: 405
edited 2011-10-17 11:12 in Propeller 1
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!
1024 x 768 - 21K
1024 x 768 - 24K

Comments

  • SnailySnaily Posts: 1
    edited 2011-10-13 05:28
    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_brainoprof_braino Posts: 4,313
    edited 2011-10-13 08:49
    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 JakackiPeter Jakacki Posts: 10,193
    edited 2011-10-13 09:02
    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.
  • JBWolfJBWolf Posts: 405
    edited 2011-10-13 17:08
    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.Heater. Posts: 21,230
    edited 2011-10-14 05:32
    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 freedmanfrank freedman Posts: 1,983
    edited 2011-10-14 06:44
    Heater. wrote: »
    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.jrjr. Posts: 45
    edited 2011-10-14 21:56
    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
  • JBWolfJBWolf Posts: 405
    edited 2011-10-15 03:35
    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.
  • JBWolfJBWolf Posts: 405
    edited 2011-10-15 03:37
    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.
  • JBWolfJBWolf Posts: 405
    edited 2011-10-15 03:51
    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.
  • JBWolfJBWolf Posts: 405
    edited 2011-10-15 04:05
    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.
  • JBWolfJBWolf Posts: 405
    edited 2011-10-15 04:35
    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!
  • JBWolfJBWolf Posts: 405
    edited 2011-10-15 07:21
    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?
  • JBWolfJBWolf Posts: 405
    edited 2011-10-15 07:26
    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 freedmanfrank freedman Posts: 1,983
    edited 2011-10-15 08:20
    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 freedmanfrank freedman Posts: 1,983
    edited 2011-10-15 08:24
    JBWolf wrote: »
    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
  • JBWolfJBWolf Posts: 405
    edited 2011-10-16 08:51
    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 freedmanfrank freedman Posts: 1,983
    edited 2011-10-16 10:55
    JBWolf wrote: »
    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
    '----------------------------------------------
    
    
    
  • kbashkbash Posts: 117
    edited 2011-10-16 23:34
    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 freedmanfrank freedman Posts: 1,983
    edited 2011-10-17 00:08
    kbash wrote: »
    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
  • JBWolfJBWolf Posts: 405
    edited 2011-10-17 07:45
    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?
  • photomankcphotomankc Posts: 943
    edited 2011-10-17 08:32
    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 JakackiPeter Jakacki Posts: 10,193
    edited 2011-10-17 08:42
    If you can use bipolar motors then an easy to use chip that will do 128 step (smooth as) microstepping is the L6470 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.
  • photomankcphotomankc Posts: 943
    edited 2011-10-17 11:12
    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.
Sign In or Register to comment.