XBee and Propeller controlled servo question
xanadu
Posts: 3,347
I have a robot with a motor contoller that has PWM inputs and a Propeller Proto Board. I have it working just fine using the XBee object. I added the Two_Servo_Assembly.spin I found in the OBEX to use a cog to keep the servos moving while the Prop does other tasks. I'm a little stuck right now and I'm not quite sure why this isn't working.
Right now I get the command echoed back to me, but the servo's don't turn. Everything works in the demo code, but when I move it into my code for listening for a keypress via XBee wireless something is going wrong.
The movement commands act as toggles, instead of holding down a key i would like to press it once, then listen for a stop command.
Any help would be great and thanks in advance!
Right now I get the command echoed back to me, but the servo's don't turn. Everything works in the demo code, but when I move it into my code for listening for a keypress via XBee wireless something is going wrong.
The movement commands act as toggles, instead of holding down a key i would like to press it once, then listen for a stop command.
Any help would be great and thanks in advance!
CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 ' Set pins and Baud rate for XBee comms XB_Rx = 0 ' XBee Dout XB_Tx = 1 ' XBee Din XB_Baud = 9600 right = 12 'servo left = 13 'servo ' Carriage return value CR = 13 OBJ XB : "XBee_Object" VAR long Pause, Pulsout long position1, position2 'The assembly program will read these variables from the main Hub RAM to determine Pub Start | DataIn XB.start(XB_Rx, XB_Tx, 0, XB_Baud) ' Initialize comms for XBee XB.Delay(1000) ' One second delay Pause := clkfreq/1_000 Pulsout := clkfreq/500_000 XB.AT_Init 'fast AT Command mode XB.Tx("1") 'ready Repeat DataIn := XB.RxTime(1000) ' Wait for byte with timeout If DataIn == "d" position1:=180_000 'Start sending 2.25ms servo signal high pulses to servomotor 1 (CCW position) position2:=40_000 'Start sending 0.5ms servo signal high pulses to servomotor 2 (CW position) XB.Tx("d") If DataIn == "w" position1:=180_000 'Start sending 2.25ms servo signal high pulses to servomotor 1 (CCW position) position2:=40_000 'Start sending 0.5ms servo signal high pulses to servomotor 2 (CW position) XB.Tx("w") If DataIn == "s" position1:=180_000 'Start sending 2.25ms servo signal high pulses to servomotor 1 (CCW position) position2:=40_000 'Start sending 0.5ms servo signal high pulses to servomotor 2 (CW position) XB.Tx("s") If DataIn == "a" position1:=180_000 'Start sending 2.25ms servo signal high pulses to servomotor 1 (CCW position) position2:=40_000 'Start sending 0.5ms servo signal high pulses to servomotor 2 (CW position) XB.Tx("a") If DataIn == "u" position1:=180_000 'Start sending 2.25ms servo signal high pulses to servomotor 1 (CCW position) position2:=40_000 'Start sending 0.5ms servo signal high pulses to servomotor 2 (CW position) XB.Tx("u") Else XB.Tx(".") 'waiting PUB Demo p1:=@position1 'Stores the address of the "position1" variable in the main Hub RAM as "p1" p2:=@position2 'Stores the address of the "position2" variable in the main Hub RAM as "p2" cognew(@TwoServos,0) 'Start a new cog and run the assembly code starting at the "TwoServos" cell 'The new cog that is started above continuously reads the "position1" and "position2" variables as they are changed by ' the example Spin code below DAT 'The assembly program below runs on a parallel cog and checks the value of the "position1" and "position2" variables in the ' main RAM (which other cogs can change at any time). It then outputs two servo high pulses (back to back) each corresponding ' to the two position variables (which represent the number of system clock ticks during which each pulse is outputed) and ' sends a 10ms low part of the pulse. It repeats this signal continuously and changes the width of the high pulses as the ' "position1" and "position2" variables are changed by other cogs. TwoServos org 'Assembles the next command to the first cell (cell 0) in the new cog's RAM Loop mov dira,ServoPin1 'Set the direction of the "ServoPin1" to be an output (and all others to be inputs) rdlong HighTime,p1 'Read the "position1" variable from Main RAM and store it as "HighTime" mov counter,cnt 'Store the current system clock count in the "counter" cell's address mov outa,AllOn 'Set all pins on this cog high (really only sets ServoPin1 high b/c rest are inputs) add counter,HighTime 'Add "HighTime" value to "counter" value waitcnt counter,0 'Wait until cnt matches counter (adds 0 to "counter" afterwards) mov outa,#0 'Set all pins on this cog low (really only sets ServoPin1 low b/c rest are inputs) mov dira,ServoPin2 'Set the direction of the "ServoPin2" to be an output (and all others to be inputs) rdlong HighTime,p2 'Read the "position2" variable from Main RAM and store it as "HighTime" mov counter,cnt 'Store the current system clock count in the "counter" cell's address mov outa,AllOn 'Set all pins on this cog high (really only sets ServoPin2 high b/c rest are inputs) add counter,HighTime 'Add "HighTime" value to "counter" value waitcnt counter,LowTime 'Wait until "cnt" matches "counter" then add a 10ms delay to "counter" value mov outa,#0 'Set all pins on this cog low (really only sets ServoPin2 low b/c rest are inputs) waitcnt counter,0 'Wait until cnt matches counter (adds 0 to "counter" afterwards) jmp #Loop 'Jump back up to the cell labled "Loop" 'Constants and Variables: ServoPin1 long |< 12 '<------- This sets the pin that outputs the first servo signal (which is sent to the white ' wire on most servomotors). Here, this "7" indicates Pin 7. Simply change the "7" ' to another number to specify another pin (0-31). ServoPin2 long |< 13 '<------- This sets the pin that outputs the second servo signal (could be 0-31). p1 long 0 'Used to store the address of the "position1" variable in the main Hub RAM p2 long 0 'Used to store the address of the "position2" variable in the main Hub RAM AllOn long $FFFFFFFF 'This will be used to set all of the pins high (this number is 32 ones in binary) LowTime long 800_000 'This works out to be a 10ms pause time with an 80MHz system clock. If the ' servo behaves erratically, this value can be changed to 1_600_000 (20ms pause) counter res 'Reserve one long of cog RAM for this "counter" variable HighTime res 'Reserve one long of cog RAM for this "HighTime" variable fit 'Makes sure the preceding code fits within cells 0-495 of the cog's RAM {Copyright (c) 2008 Gavin Garner, University of Virginia MIT License: Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. The software is provided as is, without warranty of any kind, express or implied, including but not limited to the warrenties of noninfringement. In no event shall the author or copyright holder be liable for any claim, damages or other liablility, out of or in connection with the software or the use or other dealings in the software.}
Comments
Just a note: White space is your friend. Listings with generous spacing -- that is, blank lines between distinct sections -- are always easier to read and troubleshoot. Also, the case structure would be useful in your program.
In this example you can see that case is a little easier on the eyes. It also let's you use upper and lower case input (as I did with the "d") much more easily than the if (condition) structure.
You do realize that every command uses the same servo position, right? Perhaps that's why you're not seeing any movement.
And, finally, for what it's worth... there are better servo objects available than what you're using, including my own:
-- http://obex.parallax.com/objects/445/
A well-crafted object should not require you to changes its source to use it as is the case with that dual-servo object you're using. Well behaved objects should allow you to specify which pins to use and, to the greatest extent possible, be clock frequency agnostic. Mine and others do both.
You're not calling the Demo method, you simply have it built into your code. Your code loops back to the repeat before then because Demo is an atomic block of code (it's a public method) -- it doesn't run inline as you're believing it does. In the editor you should see Demo having a different background color that Start; this is the clue that they are separate sections of code.
The delay usually means you have a waitcnt rollover error.
So are those of us that could help you.... This is common problem in the forums: a well-intentioned poster says, "My program doesn't work." but doesn't provide a full explanation of what it should do. Most of us are good programs, not so good at mind reading. A programmer's intentions are not always obvious from code.
Also, if you attached an archive of your project then others could look at the other objects to see if there are some issues. I suspect the .delay method in the XBee object may have a problem that is causing your start-up delay.
Sorry for the lack of info, I know what you mean.
What I'm trying to do is toggle two continous rotation servos using an XBee and Prop Proto Board. I need to be able to press the "a" key to start two servo's turning, then press the "u" key to stop them. I have setup the code to make is work like a push button, but not a toggle switch. This project came over from a Basic Stamp board because the Basic stamp can't run the servos and listen for a stop command at the same time. Just imagine a BOE Bot (w/prop board), controlled via XBee, and all that needs to move are the wheels, but they need to toggle on/off.
I thought I was going about this pretty simple. It seems like no matter what I do part of the code will work, and part will not.
I'll check out the waitcnt error. Is this something viewport would help a lot with?
I don't use Viewport, so I don't know if it's helpful or not.
Yes, I know they all output the same but go and stop works fine for now. I guess I'll check for other servo drivers. Thanks a lot!
I'd love to see it with your servo driver, I'm looking at it now. As you can already tell I need a lot more time with the Prop book, but this is on the side for fun and I'd like to get it going so thanks!
I've attached the project for you to play with (it compiles, but you'll have to test). Also, I'm using "instant" servo commands, that's the ", 0" in the third parameter of the set method. In practical use you may want to change this to 100 or greater so that the servo ramps to the new position. That's one of the nice features of my servo driver; it includes position/speed ramping without using more than one cog.
Here's a video of it in action - http://www.youtube.com/watch?v=XSe5nsexfQk so much to do.... so little time. Thanks again JohnnyMac!!