PDA

View Full Version : Trouble passing variable (address) values between objects



squidx
02-19-2007, 08:59 AM
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[0]) from both objects.

The following is what I'm basing things on: (note that \[\ 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\[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\[0\] 'starts at zero
waitcnt(1_000_000+cnt)
TV.out(0) 'clears screen
TV.str(String("New Reading: "))
TV.dec(Pos[0])




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

Main file



VAR
long Loc\[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\[3\] ' do I need this or can I just use Pos if if I pass it?

PUB start(Pos)
Loc := long\[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[0]: "))
TV.dec(Loc[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

Mike Green
02-19-2007, 09:31 AM
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[ Pos]" only copies the value once, at the start of the routine. Use "long[ 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).

squidx
02-23-2007, 02:04 AM
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[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[Pos]), and it won't accept parameters like TV.dec(long[Pos]), 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[9] ' stack space for cog reading encoder
long direction

Pub main
dira[16]~~
dira[6]~
dira~


Init ' encoder in new cog

outa[16] := %1 'visual feedback



video_out.start(@Pos)
video_out.checkforinput(@Pos)

{ 'example of reading Pos[0]
repeat
reading := Pos[0] 'starts at zero
waitcnt(1_000_000+cnt)
TV.out(0) 'clears screen
TV.str(String("New Reading: "))
TV.dec(Pos[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[6] test
long Stackd[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[0]: "))
TV.dec(Long[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[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[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)

Litefire
03-23-2007, 10:12 AM
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?

Litefire
03-23-2007, 11:06 AM
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[ 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[ 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

Litefire
03-24-2007, 04:56 AM
squid, did you ever get your issue resolved?

squidx
03-29-2007, 04:40 AM
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! http://forums.parallax.com/images/smilies/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[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[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 ) '[+/-]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[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

Litefire
03-30-2007, 05:50 AM
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 :( ). 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

squidx
03-30-2007, 07:14 AM
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 Stabler
03-30-2007, 07:21 AM
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

squidx
03-30-2007, 07:46 AM
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