Shop OBEX P1 Docs P2 Docs Learn Events
Trouble passing variable (address) values between objects — Parallax Forums

Trouble passing variable (address) values between objects

squidxsquidx Posts: 33
edited 2007-03-29 23:46 in Propeller 1
Hi,

I've looked at a few examples, and thought I could do this, but frustratingly, I seem to be missing the point.

I'm trying to pass the address of the Quad Encoder's output to a display routine that I will be running in its own cog. At this point, I can't even get it to run in a different object, so I haven't even started on making it its own cog.

I would do it all in one object, but I want to be able to access the encoder output (Loc[noparse][[/noparse]0]) from both objects.

The following is what I'm basing things on: (note that \[noparse][[/noparse]\ seems to allow showing the square bracket in the posting)

Main File (works great, tv output shows updated Pos. "encoder" is the quad encoder, "tv" is TV_Terminal)
VAR
    long Pos\[noparse][[/noparse]3\]  'Create buffer for two encoders (plus room for delta position support of 1st encoder)

PUB main
    Init
    CheckForInput

PUB init
      Encoder.Start(2, 1, 1, @Pos) 'Start continuous two-encoder reader (encoders connected to pins 8 - 11)
        '(StartPin, NumEnc, NumDelta, PosAddr)

PUB CheckForInput

  repeat
      reading := Pos\[noparse][[/noparse]0\]    'starts at zero
      waitcnt(1_000_000+cnt)
      TV.out(0) 'clears screen
      TV.str(String("New Reading: "))  
      TV.dec(Pos[noparse][[/noparse]0])




Now here's the one that doesn't work:

Main file
VAR
     long Loc\[noparse][[/noparse]3\]     
PUB main
    Init
    video_out.start(@Pos)

PUB Init   'ultimately want to run this in new cog
      Encoder.Start(2, 1, 1, @Pos) 'Start continuous two-encoder reader (encoders connected to pins 8 - 11)
        '(StartPin, NumEnc, NumDelta, PosAddr)




Video output file and object

VAR 
   Long Loc\[noparse][[/noparse]3\] ' do I need this or can I just use Pos if if I pass it?

PUB start(Pos)
     Loc := long\[noparse][[/noparse]Pos\]  ' since this is constantly changing, I want to use the address, not a one-off value pass
     TV.Start(12)                                'Start TV Terminal for output
     repeat
         waitcnt(1_000_000+cnt) 'prevents excessive flicker
         TV.out(0) ' clears screen
         TV.str(string("Test"))
         TV.out(13)   'new line
         TV.str(string("Pos[noparse][[/noparse]0]: "))
         TV.dec(Loc[noparse][[/noparse]0])  




So although the technique works as a single file, when I try to pass the Pos address into Loc, it doesn't work.

Any thoughts anyone? Do I need to use @@?

Thanks,

Alex

Post Edited (squidx) : 2/19/2007 1:05:51 AM GMT

Comments

  • Mike GreenMike Green Posts: 23,101
    edited 2007-02-19 01:31
    You're mixing several different things.

    1) You don't need "Loc" declared in the video output file. In fact, that's why it doesn't do what you want.

    2) The "Loc := long[noparse][[/noparse] Pos]" only copies the value once, at the start of the routine. Use "long[noparse][[/noparse] Pos]" in the "TV.dec()" call.

    3) Your start routine for the video stuff won't ever return. That may be what you want.

    4) You don't need "@@". It's used in assembly or when tables are statically created in a DAT section since the compiler doesn't know where things will be placed in memory at compile time. Data addresses are known to the compiler as relative to the start of the object's storage. When you use "@" in Spin, the compiler adds the starting address of the object's data storage at run-time. If you make a table containing addresses, you need to use "@@" to tell the compiler to add the starting address of the data storage. (I hope this helps rather than confuses further).
  • squidxsquidx Posts: 33
    edited 2007-02-22 18:04
    Hi Mike,

    Thanks so much! That advice is right on. I now have 2 new questions!

    1) The encoder code allows for many encoders to be read, as well as delta, a parameter which I don't use. You get at the first encoder through Pos[noparse][[/noparse]0], and I have been under the impression you get at the second through Pos, but I've only been using one encoder while I try to get this subroutine going.

    Since my call is TV.dec(long[noparse]/noparse]Pos]), and it won't accept parameters like TV.dec(long[noparse][[/noparse]Pos[size=2), how do I read the other encoder(s)? Thoughts?

    2) I would like this to be running in its own cog so that I can just call it, start seeing the feedback, but get back to my calling routine and not have to worry about it again. When I try to call a cog, strange things start happening, like maybe I'm overwriting memory: the screen starts flickering and buzzing, the motors, which are on a serial board start to run (!) and it just seems crazy.

    I'll put in my new code here for the calling file and for the quad display file, in a state that is currently working, just not in a cog.

    Thank you so much for your help. You must be able to tell I'm new at this, particularly addressing multiple processors!

    Alex

    CON
    _clkmode = xtal1 + pll16x
    _xinfreq = 5_000_000
    
    OBJ
    ' ExtSerial : "Extended_FDSerial"
    '  Num   :       "Numbers"
    '  TV    :       "TV_Terminal"
      Encoder : "Quadrature Encoder"
    '  Beeps: "beeper_obj"
      video_out : "vid_monitor"
    
    
    Var
    ' from encoder object
      long Pos                            'Create buffer for two encoders (plus room for delta position support of 1st encoder)
      long reading
      long Stack[noparse][[/noparse]9] ' stack space for cog reading encoder
      long direction
    
    Pub main
      dira[noparse][[/noparse]16]~~
      dira[noparse][[/noparse]6]~
      dira~
    
    
      Init       ' encoder in new cog
    
      outa[noparse][[/noparse]16] := %1      'visual feedback
     
    
      
     video_out.start(@Pos)
     video_out.checkforinput(@Pos)
     
    {        'example of reading Pos[noparse][[/noparse]0]
      repeat
          reading := Pos[noparse][[/noparse]0]    'starts at zero
          waitcnt(1_000_000+cnt)
          TV.out(0) 'clears screen
          TV.str(String("New Reading: "))  
          TV.dec(Pos[noparse][[/noparse]0])
          TV.out(13)
          }
    PUB Init
      Encoder.Start(2, 1, 0, @Pos) 'Start continuous two-encoder reader (encoders connected to pins 8 - 11)
            '(StartPin, NumEnc, NumDelta, PosAddr)
    



    CON
    _clkmode = xtal1 + pll16x
    _xinfreq = 5_000_000
    
    OBJ
      TV    :       "TV_Terminal"
      Beeps: "beeper_obj"
    
    Var
    ' from encoder object
                              'Create buffer for two encoders (plus room for delta position support of 1st encoder)
      long reading
      long prev
      long current
      long temp 'for value of ina[noparse][[/noparse]6] test
      long Stackd[noparse][[/noparse]9] ' stack space for cog display
      long direction
      long emergency
      long rate
      long limit
      byte video_cog
      
      
    Pub Start(Pos)
    
      TV.Start(12)                                'Start TV Terminal for output
      TV.str(string("Test"))
      TV.out(13)
      TV.str(string("Pos[noparse][[/noparse]0]: "))
      TV.dec(Long[noparse][[/noparse]Pos])  
    
    {examples of failed cog-starting code:}
    '  video_cog := cognew(CheckforInput(Pos),@Stackd) {set up as new cog} 
    '  checkforinput(@Pos)
    
    PUB CheckForInput(Pos)
    {So far, works as a function, but not in a cog;
      also, how to address Pos[noparse][[/noparse]0] vs Pos?}
    
      repeat
          waitcnt(1_000_000+cnt)   'allows ok screen refresh
          TV.out(0) 'clears screen
          TV.str(String("New Reading: "))  
          TV.dec(Long[noparse][[/noparse]Pos])
          TV.out(13)
          TV.str(String("Status: "))
          if ina~~
            TV.str(String("Emergency Stop Button Pressed"))
          elseif ina~
            TV.str(String("Ready"))
          TV.out(13)
    
    

    [/size]
  • LitefireLitefire Posts: 108
    edited 2007-03-23 02:12
    I'm having issues with Quad Encoder as well. One encoder works relatively well (the right one and the values have significant play, but that may be due to when i check the code), but the other one only returns garbage. such as a relatively static count of about 224 when the left motor is not moving (nor has it since the prop booted up) at all. include the fact that the values flip frequently from positive to negative... that == Confusion.

    I found the motor minder object, and was very excited, but it isn't designed for quadrature (boo!), so it's really no good for me (it's also designed for 1 pulse per revolution, ew). does anyone else have a quadrature encoder object that they could lend me?
  • LitefireLitefire Posts: 108
    edited 2007-03-23 03:06
    i attached my code, it's too much of an issue to paste into the forum. Mike, the motor object is working like a charm thanks to you, but this encoder thing is really bumming me out.

    the values that i'm reading out of encoder (which are held in a long array in motortest) are doing strange things. they're flipping around in the case of the left motor and not returning valid responses, it's receiving an incorrect number of pulses per revolution (documented as 360 but is recognized at more like 600 but this varies too). most visibly, in the code i have an IF statement that isn't functioning correctly at all. when i state:

    IF encoderstack[noparse][[/noparse] 1] => 3600 
      'stop motors
      'debug out that it's done
    
    



    it won't ever perform the if, but will visibly pass the setpoint when displaying values. i watch it go from 3200 to 3644 to 3800... and nothing happens.

    BUT... if i do this:

    IF LONG[noparse][[/noparse] encoderstack] => 3600
      'stop motors
      'debug finished
    
    



    it trips immediately, no questions asked. then proceeds to display values that start at around 12...

    i'm outta my league right now with this, time to bring the cavalry back in on the problem.

    also, if we get it working can you give me some pointers on integrating it into the setmotor object?

    ~~Brian
  • LitefireLitefire Posts: 108
    edited 2007-03-23 20:56
    squid, did you ever get your issue resolved?
  • squidxsquidx Posts: 33
    edited 2007-03-28 20:40
    Yes, I did, thanks... I had been testing with the number-of-encoders parameter set for 1, and then expecting to read the second! D'oh! shakehead.gif And I spent a bit of time learning more about cogs, and got that problem taken care of also.

    How about you? Any new results? I have a couple suggestions, based on what I ran into:

    * Encoders were giving sketchy results until I started using pullup resistors (I didn't figure this out myself - I'm using the TRD-S2500BD encoders, and I called them... )

    * I have been able to successfully compare position with a target like what is frustrating you... I'm not sure how it's different from yours, except that I use more parentheses. I also wait a moment (between 1/10 and 1/2 sec usually) before checking (this is more of a motor board issue):
      target := x_data[noparse][[/noparse]request] 'x_data is a sequence of targets in a data structure
      'check desired direction: compare target with current location
      'if target is greater, then go forward; if less, go backwards
    
      if(target > Pos[noparse][[/noparse]0]) '
        beeps.beep(1) ' just a little beep routine for additional feedback
      'moving forwards: 'I have routines that communicate serially with a driver board
        steps.slew_x(1,18_000, 5000 ) '[noparse][[/noparse]+/-]steps,rate,slope    '1,20_000, 60_000 for EAD microstep
        waitcnt(30_000_000+cnt) 'wait until moving starts to start checking?
    
        repeat while(Pos[noparse][[/noparse]0] <= (target-400))   'stop before getting too close
            waitcnt(800_000+cnt) 
        steps.kill
        beeps.beep(2)
    
    



    This code is for moving the motor quickly. I stop it, wait for the motor board to gather its thoughts, then start moving slowly until I am within 5 encoder units of the target, which is well under 1mm.

    * For what it's worth, I also had a problem coming back to stopping at zero... -1 or 1 works much better, and there's no appreciable difference.

    Hope this helps. I can send you the complete files if you like, including the video output in a cog bit. It's not working perfectly yet, but the encoders aren't a problem right now.

    Alex
  • LitefireLitefire Posts: 108
    edited 2007-03-29 21:50
    i got mine working finally, bad power connections were causing sporadic periods of functionality... which we threw out as noise.

    just a matter of trial and error calibrating. i've got it going fairly straight, and have asked mike green to look into a way to add feedback to the speed loop (i'm using a home-brew h-bridge after my MD23 motor controller crapped out without working once [noparse]:([/noparse] ). and i've got it making good 90deg turns from a standstill... later i'm going to try to calibrate high-speed turns. gonna be quite interesting.

    but i'm working on integrating my Rangefinders and other sensors, when i was powering them them from the 5V line on the protoboard something started buzzing (prob the 5V reg) and am wiring up a new one with a standard sized heat sink, not the chopped off one mounted on the board. hopefully the dedicated device can put out the required power... oh well i'll find out in 10 min.

    glad that you have your project working... i've got 5 cogs dedicated to my motors, instead of the one or two i would have needed with the serial board... so i'm jealous. it's getting tight, but right now is really holding together nicely.

    congrats on your project, what' it for anyway?

    ~~Brian
  • squidxsquidx Posts: 33
    edited 2007-03-29 23:14
    It's an automated micropipet system for a cancer research lab. The pipet is programmable, so I have the propeller driving x,y,z motors to different locations on 96-well plates, picking up pipet tips (stab the pipettor into the tip, which is about a 4mm target), pulling the tip eject button with a solenoid, and essentially doing a liquid handling task moving volumes of between 3-10nanoliters between various trays. The ultimate task is for working with toxic materials in a long assay process which would be extremely time-consuming and boring for a person.

    The project has a lot of components, but I'm pretty close on the x-y axes. I have been planning to use some backup optical interference sensors just to calibrate better at various locations by adding an offset to my encoder info, but the encoders have been so good I don't think I'll be doing that. I think I'd rather have a hard 'home' location where I jam the motors up against some fixed points (gently!) and then restart my encoder cog. This way I'll still reduce my accumulated errors regularly without having to do very careful sensor positioning.

    In a sense, this is much more of an automation exercise than a robot exercise, but I call it a robot anyway! I've written some fun sound routines, so it does seem to have a bit of a personality!

    I did try working on my own stepper drivers, but the serial board is really good for my needs. If I needed immediate responses, though, I wouldn't have done it. There is some latency in the communications.

    What's your project?

    Alex
  • Graham StablerGraham Stabler Posts: 2,510
    edited 2007-03-29 23:21
    Why do you feel the need for encoders, steppers don't drop steps unless they are too small or there is a serious error, is it just so it stops if something does go wrong?

    Graham
  • squidxsquidx Posts: 33
    edited 2007-03-29 23:46
    I have not had that experience with steppers, unfortunately. I initially expected to be able to say "go 1000 steps" and have that be bulletproof, and only use sparse external sensing (like a couple of optical interrupters) to confirm my results. However, I have found that either with a home-grown MOSFET setup, or with a separate driver board, I do not get anywhere near a reliable output from the stepper motors. For example, if I run them in one direction for 1000 steps and then back again, they *only sometimes* return to their exact starting place.

    I'm not sure why this happens. It may well be because I haven't hooked things up right, or because my load is too massive for the steppers, but I don't think so -- my original tests were on small steppers, no load.

    Using the encoders is really great, and for my particular purposes it would be just unwise to run open-loop anyway. I have 4mm targets to hit on a run of 36"x14" (sorry to mix units!). The encoders can get me within 1mm.

    Alex
Sign In or Register to comment.