Shop OBEX P1 Docs P2 Docs Learn Events
stepper record and playback — Parallax Forums

stepper record and playback

OwenOwen Posts: 100
edited 2008-01-11 16:21 in Propeller 1
I'm currently trying to write an object that will record the propeller controlled movement of a stepper motor to an SD card and then be able to play it back again. My setup is an encoder that is used for an input device which is programed on the propeller to step a stepper motor for every pulse of the encoder. I'm having trouble with how to approach this problem, all my attempts I'm sure have been far too complicated. Anyone have any simple ideas?

Owen

Comments

  • Fred HawkinsFred Hawkins Posts: 997
    edited 2008-01-08 04:04
    "the propeller controlled movement of a stepper motor" suggests that you know the when and the what of the direction commands. Keeping track of the change of these choices would be much simpler than recording the positional sensing of the stepper motor. The first requires a time stamp and a decent summary of the command ranges.

    The second solution (encoder) would generate a lot denser information stream (ie bigger) with less useful data and possibly more noise.
  • OwenOwen Posts: 100
    edited 2008-01-08 04:39
    this is actually for a camera control device I'm building,
    the encoder is connected to a handwheel as a user interface to the motor and is not used as motor feedback. the faster or slower the handwheel is turned the faster or slower the motor moves. ultimately I am controlling the way a camera moves, one handwheel is the panning motion and another is the tilting motion. the idea is to playback the camera motion exactly how it was recorded. I was hoping to track the motors steps over a given amount of time, like a record of of Xaxis and Yaxis every millisecond. Recording the location of the motor is not hard for me it's how to smoothly playback the information that I'm having difficulties with. Anyone done anything similar?
  • Sparks-R-FunSparks-R-Fun Posts: 388
    edited 2008-01-08 17:13
    Since storage space does not present a problem, you might be able to use a data streaming approach. The uncompressed streaming rate should match you maximum movement rate. For each discrete time slice simply record (or playback) the step and direction status for each motor.

    I expect data of this type will be highly compressible. However, it may not be worth the effort to compress it if there is no need to conserve storage space.


    - Sparks
  • mosquito56mosquito56 Posts: 387
    edited 2008-01-08 18:35
    I am just curios why you feel the need to record the info every millisecond? Since you are using a human operated system (handwheels) wouldn't every second be sufficient?

    · I have done extensive work with decoding data from a gps and found that by slowing down the info to a more managable level it is easier to decode and use. Once it is working you can optimize for speed.

    ·What program are you using to interperet the data? If the program cannot prosses fast enough you will lose data when trying to decode.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Mosquito: An animal which buzzes in your ear and never stops. He may byte you, he may nibble you, but you will know you were bit.


    Technologically challenged individual, Please have pity.
  • StefanL38StefanL38 Posts: 2,292
    edited 2008-01-08 20:34
    Hello Owen,

    Did you already test a program?

    what does the steppermotor do if you playback the recorded pulses?

    could you post your code here? (with a lot of comments !)

    do you have an oscilloscope for displaying the created stream of steppermotorpulses?

    what are you recording exactly?

    Is it an incremental encoder?
    If so - if you manage to record every millisecond the amount of encoder pulses counted
    these amount of pulses is directly proportional to the speed of the stepper-motor

    if you have an absolute encoder you have to calculate the value-differencies.
    In this case you have to take care of turning around the zero-position of the encoder.

    you have to calculate from encoderpulses to motorsteps per second (=stepperfrequency) and then set a
    stepperpulse-routine to that stepperfrequency. Direction could be inside the sign of the value.

    this stepperpulse-routine creates pulses on an IO-Pin endlessly with the frequency READ from
    a variable (or in Assembler from a certain RAM-adress)

    Lets call this variable "StepFreq"

    another routine is reading out the recorded encoderpulses every millisecond, calculating the stepperfrequency
    and STORES the stepperfrequency in the same variable "StepFreq"
    So the stepperfrequency "0" stops the stepperpulseroutine


    And here milliseconds might be a problem:
    If you use a steppermotor in fullstep or halfstep-mode (in microstep-mode it could be higher)

    The frequency for starting the steppermotor in halfstep-mode from zero is around or lower than 1000 Hz (= 1 pulse per millisecond)

    Here it might be better to have a greater timebase f.e. 10 milliseconds

    So this would give a minimum of 2 to 10 pulses per time"frame" for the stepperpulse-routine to "send out"
    to the IO-PIN

    Steppermotors don't like it if you change the frequency too fast. Then you will loose control and the rotor of the steppermotor
    is only vibrating instead of turning around.

    The limit of this frequencyCHANGE depends on the type of the steppermotor

    explaining with extreme (and unrealsitic) values just to make it clear:

    let's say your steppermotor is running at a speed of 1000 stepperpulses per second. (=1000 Hz)
    If you would CHANGE the frequency within 1 step to another from 1000 Hz to 100.000 Hz
    how should the mechanical rotor accelerate within 1/100.000 = 10 microseconds to a speed thats a 100times higher?

    That's not possible.

    So

    It might be possible to do all this inside 1 mainloop
    but i suggest for the beginning have one cog for the stepperpulseroutine

    and another cog for the SD-Card-reading

    give in more concrete information then the forum could help you much better

    greetings

    Stefan
  • OwenOwen Posts: 100
    edited 2008-01-08 21:49
    well now I have partially working code. I'm constantly tracking the position of the motor when it's recording and storing the position value on the sd card every 1/100sec then i take the recorded position and subtract the previous recorded position to get the steps in the time period. then I convert this to a frequency and output it with freqout updating every 1/100sec. I do get playback now but it always plays back faster than it recorded so now I need a way to sync the periods. I guess my problem is that I never accounted for the clock cycles it takes to run the code and I just used a wait count command. i'll try to clean and comment my code and post it soon as I get a chance. at least it moves! no on to the timing...
    thanks,
    Owen
  • StefanL38StefanL38 Posts: 2,292
    edited 2008-01-08 22:55
    Hello Owen,

    that's a quick answer (just heard my mobilephone buzz (SMS-email notification)


    are you using the function "PUB FREQOUT(Pin,Duration, Frequency)?"
    it uses the waitcnt-command which stops the COG COMPLETELY !

    use the function "PUB FREQOUT_Set(Pin, Frequency)" instead.
    It uses the hardwarecounters to create the frequency.
    The hardwarecounters are independend from codeexecutiontime

    This one creates the frequency INDEFINATELY.
    Initialize with Frequency zero (=no Pulses sended out
    FREQOUT_Set(Pin, 0)

    once you have startet Playback every 1/100 Secs comes an updated value
    that chances the frequency in the right way

    For stopping just call FREQOUT_Set(Pin, 0) again

    Did you understand how it is working?

    if your SD-Card-reading has runtime differencies you can avoid them
    by taking a snapshot of the cnt-value right on top of your reading-loop BEFORE start reading

    With this snapshot-value you can correct the waitcnt-delay-time
    if runtime-differencies have occurred reading the SD-card.

    and you have to make sure that the reading is done in less than 1/100 Sec
    or whatever your timeframe is

    greetings

    Stefan
  • Graham StablerGraham Stabler Posts: 2,507
    edited 2008-01-09 00:47
    So you basically want to record the output of a manual pulse generator MPG as the CNC boys call it and then be able to play it back so you can record a camera motion sequence and then play it back.

    You could use the counters, use one the measure the frequency which is then stored at a regular time interval and then use the counter again to reproduce it.

    You can forget all about positions if you do this, it just works out.

    Graham
  • deSilvadeSilva Posts: 2,967
    edited 2008-01-09 00:54
    There is most like no need for extra "counters", CNT will do fine.
  • OwenOwen Posts: 100
    edited 2008-01-09 03:13
    pub playback  | r, q,s, p ,T , dir, prev, current, output, sync
    
       
      sd.mount(22)                                                      'mounts the sd card
      sd.opendir                                                        'opens the directory on the sd card
      
      
      repeat while 0 == sd.nextfile(@tbuf)
      r := sd.popen(string("timelapsefilex.txt"), "w")                   'opens the file on the sd card
        
                                                                         'wait for switch before recording
       sync := cnt    
       repeat 1000                                                        'record 1000 periods (1000 is just a set number for testing)    
          waitcnt(sync += ((clkfreq / 1_000) * 10))                       'wait untill 10ms period 
          sd.pwrite(@coordinatex, 4)                                        'write the coordinate of the y axis to the sd card (says x but i swap them for eas of testing)
                                                                           
      sd.pclose                                                           'close the file on the sd card
        
       
     sd.popen(string("timelapsefilex.txt"), "r")                           ' open the sdcard file in read mode
    
      dira[noparse][[/noparse]enablePiny]~~                                                    'enable the motor for playback
      outa[noparse][[/noparse]enablePiny]~
    
      dira[noparse][[/noparse]dirPiny]~~
      outa[noparse][[/noparse]dirPiny] := 0        
      prepos := 0
    
      ctra[noparse][[/noparse]30..26] := %00100                                                 'setup the harware counters for the x axis  
      ctra[noparse][[/noparse]5..0] := stepPinY
      dira[noparse][[/noparse]stepPiny]~~
    
    
       sync := cnt  
    repeat
         waitcnt(sync += ((clkfreq / 1_000) * 100))                          'gives 100ms delay          
         
         q := sd.pread(@S, 4)
         if q < 0
           quit
         T:= s - p
    
         current := S                                                          '"current" is set to the firs read number from the sd card
    
         
          
          if prev < current                                                   'prev < current  cheacks direction of recorded movement
            output:= (current - prev) * 10                                    ' current - prev * 10 gives us the frequency "output" in hz
            
            outa[noparse][[/noparse]dirPiny] :=0 
            
            frqa := (output) 
                                         
                    
    
          if prev > current
            output :=(prev - current) * 10
            outa[noparse][[/noparse]dirPiny]:=1
            
            frqa := (output)   
                                       
            
    
          if prev == current                                                     ' if there is no change in the recorded position then output freq is 0  (no movement)
              output := 0
          text.dec(output)
              
          prev := current                                                        'updates the prev value before looping again
    
    



    here is the recording and playback code I'm trying to get working...
    i didn't include the code that drives the stepper motor during recording but there is another cog that moves the stepper motor and ubdates the memory location @coordinateX which is what the recording code stores on the sd card.
    I seem to have trouble with:
    sync := cnt
    repeat
    waitcnt(sync += ((clkfreq / 1_000) * 100))

    thanks,
    Owen
  • StefanL38StefanL38 Posts: 2,292
    edited 2008-01-09 10:36
    hello Owen,

    you have to put the line

    sync := cnt

    INSIDE the repeat loop

    
    repeat
         sync := cnt
         
         q := sd.pread(@S, 4)
         etc
    
        'and then tha VERY LAST thing inside your loop should be
         waitcnt(sync + ((clkfreq / 1_000) * 100))                          'gives 100ms delay          
    
    
    




    this does what i called a snapshot of the systemcounter right on the beginning of your mainloop

    now all the SD-Card-reading can take different times. It doesn't matter anymore
    because you refer to a countervalue that comes from a time BEFORE the SD-Card reading starts
    to make it really sure you have to implement a timeout inside the sd-card-reading


    in your way you are waiting 100ms and then the sd-card-reading take ADDITIONAL time
    one example with easy values

    sync := cnt let's say the 32bit cnt-value is the same as 1200ms (for easier understanding)

    now SD-Card-reading starts and takes different times in the first, the second, th third loop: 10 ms, 80ms, 5ms,

    my code does
    1200ms take cnt-snapshot
    do sd-card-reading (takes 10ms)
    waitcnt starts at 1210ms and waits until 1300ms

    first loop waitcnt(1200ms + 100ms)

    1300ms take cnt-snapshot
    do sd-card-reading (takes 80ms)
    waitcnt starts at 1380ms and waits until 1400ms

    second loop waitcnt (1300ms + 100ms)

    1400ms take cnt-snapshot
    do sd-card-reading (takes 5ms)
    waitcnt starts at 1405ms and waits until 1500ms

    third loop waitcnt(1400ms + 100ms)

    with this code you have to make sure that the sdcard-reading does take less than 100ms, becouse otherwise
    the value sync + 100ms is already through and then the waitcnt waits for almost a minute until the systemcounter
    wrappes around to zero and reaches again the value sync + 100ms

    your code does


    first loop
    do sd-card-reading (takes 10ms)
    waitcnt(1210ms + 100ms)
    waitcnt starts at 1210ms and waits until 1310ms

    second loop
    do sd-card-reading (takes 80ms)

    waitcnt(1390ms + 100ms)
    waitcnt starts at 1390ms and waits until 1490ms


    third loop
    do sd-card-reading (takes 5ms)

    waitcnt(1495ms + 100ms)
    waitcnt starts at 1495ms and waits until 1595ms

    etc.


    greetings

    Stefan

    Post Edited (StefanL38) : 1/9/2008 10:45:38 AM GMT
  • Graham StablerGraham Stabler Posts: 2,507
    edited 2008-01-09 10:54
    deSilva said...
    There is most like no need for extra "counters", CNT will do fine.

    If you use the counters then you leave your program free to do other things nearly all of the 1ms sampling period can be used for any processing you like. CNT would be used to set the length of the loop as Stefan shows.

    This is how I did my stepper motor code in essence, I had a fixed length (in time) loop in which most of the time was spent working out what frequency to send to the motor next.

    Graham
  • OwenOwen Posts: 100
    edited 2008-01-11 03:29
    Well I seem to be further on my way but now I'm running into problems with sd card writing speed. Although i don't know why? I'm not writhing much data here, just one long 100 times per second or 400 bytes a second that would be 3.2kb/s right? Is this a reasonable data rate. Is there any relatively easy way to buffer this in the cog ram?

    thanks,
    owen
  • deSilvadeSilva Posts: 2,967
    edited 2008-01-11 09:27
    (a) An SD card can write > 1 Mega Byte Per Second. It will also depend on your realisation of SPI.
    When done in SPIN you will be around 40 kBit/sec, so 5000 bytes should be feasible (=10x of what you observe)

    (b) Buffering of 400 bytes is no problem in COG
  • PhilldapillPhilldapill Posts: 1,283
    edited 2008-01-11 16:21
    Owen,
    This is somewhat similiar to what I am doing, except I am recording remote control inputs to an SD Card. I think this can be related to what you are doing.

    In my program, I have a table that stores my keycodes sent from a remote control to the propeller, then an enumerated list that interacts with the previous table to form a lookup table. On the SD Card, I simply write the "KeyNum"(the enumerated number that cooresponds to the code sent), a "comma and space", then the KeyCode(the actual code) written in Hex, then a new line. Basically, the file format looks like this:

    0, $00001B14
    3, $00001E14
    2, $00001C14
    14, $00002314
    and so on...

    What I end up with, is an easily parseable file that I can then manipulate into a record in memory. It's also easy to go in and make slight changes manually to the file. What I suggest you do, is have two components to each line: Step Direction and Delay until next instruction. Like this:

    0, 10
    0, 10
    0, 10
    0, 10
    0, 10
    0, 1000
    1, 1
    1, 1
    1, 1
    1, 1
    1, 1
    1, 1

    This simple instruction set translates into: Move LEFT 5 times with 10ms in between steps, then wait 1 second, move RIGHT 5 times with 1ms in between steps.

    Like I said, this format is easy to code a translator for. Hey, I could even give you some of my code I'm working on. It's very similiar. Each command is 1 line, and you can add as many variables as you want, like in the a.m. example, it has two. PM me if you want to colaborate.
Sign In or Register to comment.