Shop OBEX P1 Docs P2 Docs Learn Events
New to Propeller and I need some advice. — Parallax Forums

New to Propeller and I need some advice.

minitrueminitrue Posts: 17
edited 2014-03-15 19:22 in General Discussion
Hello, all

I am a physics and engineering teacher in Buffalo, NY. I have been using Basic Stamps in my classes for 5 years and am very comfortable with them.

My students recently entered a contest where they had to build a small car capable of negotiating an obstacle course and pick up items along the way for points. Their car has 4 continuous rotation servos being used as direct-drive wheels. There are also two arms on the front of the car that are each made up of two 180° servos so that the arms can rotate and elevate. Lastly, there was a continuous rotation servo that helped push the items that we picked up into a goal box. We were controlling the drive system and the pusher with a 8bit nintendo controller and we were controlling the arms haptically with 10k pots. The nintendo controller also used 2 buttons to change the speed of the car. We ideally wanted to do this wirelessly with a set of rf transceivers. We were able to do either the driving or the arms that way, but could not get them to work nicely together. Both systems became very jittery. We ended up going to the first round of our contest with a tethered car and we got second place.

The school that beat us had one kid driving by herself instead of two kids sharing duties. We want to be able to do that, and our plan is to make a controller from scratch that one girl can do by herself. We want to have four 2 axis joysticks. Two would only use the up and down function to do a tank drive system and two would be used on both axes to control the arms. We would not need the speed control functions we had since the drive could use proportional response. We would need to add one more switch or dial to control our pusher. We did not feel that a basic stamp could do this, but we tried it anyway. We do have working code, but the system is jittery because each servo is only being given instructions for 1/9th of each code loop.

I know that the propeller has 8 cogs that can work independently, and I thought we might try to run our car off of one of those.

I bought a propeller BOE a few days ago and have attached the 4 joysticks to it. I have done a lot of the SPIN tutorials on this site and have made some progress. I am going to use the four built in ADC pins for the arms and we made some RC circuits on a breadboard for reading the two drive sticks.

So far, I have been able to get readings from the drive sticks and manipulate that data into a range of values that can control a continuous servo. It works great. However, when I tried to add another servo, it still worked but the response rate slowed way down. I can't find any resources that talk about running multiple servos in multiple cogs.

This is what I have working so far:

system.Clock (80,000,000)

RC.start (0,1, @rightstick)

servo.Start

repeat

rightwheel := (94*rightstick/7) -800)
servo.Set (14, right wheel)

...and that works fine. But we want the right stick to control both right wheels. When we change the code to:

system.Clock (80,000,000)

RC.start (0,1, @rightstick)

servo.Start

repeat

rightwheel := (94*rightstick/7) -800)
servo.Set (14, right wheel)
servo.Set (15, right wheel)


...it still works but is VERY slow in responding. Can someone tell me why this is happening and what I can do about it?
Even the basic stamp could do this without an obvious delay.


What I would ultimately like to do for this project is this:

cog#1:

read right drive stick (U/D) with RC circuit
send instructions to both right wheels

cog#2:
read left drive stick (U/D) with RC circuit
send instructions to both left wheels

cog#3:
read right arm (U/D) with DAC pin and
send instructions to the right arm fixed rotation elevator

cog#4:
read right arm (L/R) with DAC pin and
send instructions to the right arm fixed rotation turntable

cog#5:
read left arm (U/D) with DAC pin and
send instructions to the left arm fixed rotation elevator

cog#6:
read left arm (L/R) with DAC pin and
send instructions to the left arm fixed rotation turntable

cog#7:
read another pot with a RC circuit and
send instructions to the pusher



I would appreciate any advice on this matter. If you know of a library or object that already exists to do something similar that would be awesome. Like I said, I already can control 1 servo, so I think I am well on my way to finishing this, I just need help with the cog assignments.

Thanks a lot!

Larry
«1

Comments

  • minitrueminitrue Posts: 17
    edited 2014-03-12 10:03
    I have the left drive stick connected now, and it is controlling a servo too, but I can't get the right stick and the left stick to work at the same time.
  • Bob Lawrence (VE1RLL)Bob Lawrence (VE1RLL) Posts: 1,720
    edited 2014-03-12 10:07
    [h=1]Set and Sequence Groups of Servos
    http://learn.parallax.com/node/252[/h]
  • Beau SchwabeBeau Schwabe Posts: 6,566
    edited 2014-03-12 10:07
    minitrue,

    Hello and welcome to the Parallax Forums!!!

    Can you pleas attach your code using the " File--> Archive--> Project... " ? That would make it easier for us to see what all is running in your code that may be causing an issue.
  • minitrueminitrue Posts: 17
    edited 2014-03-12 10:15
    Bob,

    I saw this, but I wasn't sure that it was the right way to go. It looks like this is for sending groups of servos to a bunch of predetermined points, and we want the motion to be fluid and proportional to the value of the pots in as close to "real time" as possible. Can a data set like this describes do that?
  • minitrueminitrue Posts: 17
    edited 2014-03-12 10:17
    minitrue,

    Hello and welcome to the Parallax Forums!!!

    Can you pleas attach your code using the " File--> Archive--> Project... " ? That would make it easier for us to see what all is running in your code that may be causing an issue.

    Thanks.

    .robocross.spin
  • minitrueminitrue Posts: 17
    edited 2014-03-12 10:29
    After playing a little bit more with things, it seems that the one stick controlling two servos do start up together nicely and do react in real time up to the point where they are allowed to return to center. Then there is about a 2 second delay before they start responding to the stick again.
  • minitrueminitrue Posts: 17
    edited 2014-03-12 12:33
    robocrosstry5.spin

    This code is now in the form that I think that I want it to be in, but it does not work. I have spent all day trying to make progress on this but I am at a loss.
  • Beau SchwabeBeau Schwabe Posts: 6,566
    edited 2014-03-12 13:01
    First, the items in the OBJ are assigned their own cog, and by defining each section to a cog further down in your code, you have run out of cogs.

    Since servo's only need to update every 20ms (50 times a second) then you can do most if not all of your calculations in-between this period.

    Without a complete attached archive file though it's difficult to tell what the OBJ items are doing. ... " File--> Archive--> Project... "
  • minitrueminitrue Posts: 17
    edited 2014-03-12 13:37
    First, the items in the OBJ are assigned their own cog, and by defining each section to a cog further down in your code, you have run out of cogs.

    Since servo's only need to update every 20ms (50 times a second) then you can do most if not all of your calculations in-between this period.

    Without a complete attached archive file though it's difficult to tell what the OBJ items are doing. ... " File--> Archive--> Project... "

    I can't archive it because the auto syntax checker does not like how my coginit lines are written. I have no parameters on my methods, which I don't think I need. I also don't have any stack space references because I don't really understand them.
  • Beau SchwabeBeau Schwabe Posts: 6,566
    edited 2014-03-12 13:43
    It's in the Propeller IDE used to program the Propeller under the same tab you use to save your project file.
  • minitrueminitrue Posts: 17
    edited 2014-03-12 13:47
  • Bob Lawrence (VE1RLL)Bob Lawrence (VE1RLL) Posts: 1,720
    edited 2014-03-12 13:57
    I also don't have any stack space references because I don't really understand them.

    Measuring Stack Space for Parallel Processes

    http://www.parallaxsemiconductor.com/sites/default/files/appnotes/AN019-StackSpace-v1.0_1.pdf
  • Duane DegnDuane Degn Posts: 10,588
    edited 2014-03-12 14:08
    As Beau started to say, you don't need to separate the functions out to separate cogs like you were attempting to do. Frequently extra cogs are used for custom peripherals like serial drivers and servo drivers. Generally you'll still have one main loop to perform your calculations and make decisions.

    The serial driver uses a cog, the RCTIME object uses a cog and the servo driver uses a cog. Your main loop will run in another cog which leaves you with four unused. You rarely want to use coginit to start a cog (I have never done so). Let the Propeller decide which cog to use with cognew but only when you really need another cog. I think the top object should be fine running in a single cog.

    My hexapod uses one cog (with the assistance of another cog acting as a math coprocessor) to calculate all 18 servo positions based on some pretty hairy math and it can do this at the 50Hz servo refresh frequency. Your main loop should have plenty of time to do all the work without the need to start additional cogs.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2014-03-12 14:11
    I personally like my technique for monitoring stack space. It lets you actively monitor the stack space.
  • Beau SchwabeBeau Schwabe Posts: 6,566
    edited 2014-03-12 14:11
    One thing I see is that you are running the RC time in background mode (which requires a cog)

    instead of ...

    RC.start( 0, 1, @rightwstick )

    ...use
    RC.RCTIME( 0, 1, @rightwstick )

    ...This will eliminate excessive cog usage here.

    I will look at the rest of your code later and see where there could be other optimizations.
  • Beau SchwabeBeau Schwabe Posts: 6,566
    edited 2014-03-12 15:37
    minitrue,

    See if the attached version is more like what you are wanting to do. One recommendation I would have would be to place an upper and lower limit to the value you are commanding to the servo's. This should be done within the Servo routine, but at a first glance I didn't see any evidence of input limitations. This is just in case one of your POTs fails or becomes unplugged, etc. This could be done in the 'Calculations' PUB in the attached file.
  • minitrueminitrue Posts: 17
    edited 2014-03-12 16:12
    minitrue,

    See if the attached version is more like what you are wanting to do. One recommendation I would have would be to place an upper and lower limit to the value you are commanding to the servo's. This should be done within the Servo routine, but at a first glance I didn't see any evidence of input limitations. This is just in case one of your POTs fails or becomes unplugged, etc. This could be done in the 'Calculations' PUB in the attached file.

    Beau-

    This is great! It is a little sluggish in response on the sticks. I'll try splitting up the calculations into two different cogs to get the values to the servos quicker. Thanks for the help!
  • Beau SchwabeBeau Schwabe Posts: 6,566
    edited 2014-03-12 16:17
    minitrue,

    I noticed your dividing the RCTIME values by 8 ... what is the resistance of the POTs and what are the capacitor values that you are using? .... A smaller value capacitor and less division on RCTIME could also speed things up.
  • minitrueminitrue Posts: 17
    edited 2014-03-12 16:30
    minitrue,

    I noticed your dividing the RCTIME values by 8 ... what is the resistance of the POTs and what are the capacitor values that you are using? .... A smaller value capacitor and less division on RCTIME could also speed things up.


    I am using .1 µF caps and the parallax 2 axis joysticks, which I believe have 10K ohm pots.


    What would I need to do to the code to get the two joysticks for the arms to get data through the dedicated AD pins rather than using rc circuits on the breadboards? Is that worth doing?
  • Beau SchwabeBeau Schwabe Posts: 6,566
    edited 2014-03-12 16:35
    Just for kicks try using two .1uF's in series, that will effectively make a .05uF. If that works out better then a standard .047uF could be used. The RCTIME however is going to be your bottle neck, the calculations don't take any time at all really, I just separated it more for aesthetic appearance more than anything else.
  • JasonDorieJasonDorie Posts: 1,930
    edited 2014-03-12 16:36
    One of the best things you can do *before* you change anything is see how much time each piece is taking relative to the others.

    Do something like this:
    repeat
      startTime := cnt
    
      ' do a bunch of work here
    
      delta := cnt - startTime
      pst.dec( delta )
      pst.out( 13 )     ' Add a carriage return
      pst.out( 10 )     ' Add a newline
    

    It's worth noting that adding the pst commands will slow down your loop, but they won't affect the calculation timing. The results you get back are clock cycles, so dividing by the clock frequency will tell you how much actual time the calculations in the 'do a bunch of work' blob are taking. Even without converting to seconds, you'll be able to see how much time things are taking relative to each other. For example, if FunctionA was 190,000 and FunctionB was 4,000,000, you'd know that FunctionB was taking about 20 times longer, and so you should focus your effort on that one.

    If I'm not mistaken, the RCTime code is sensitive to the components attached to it. Rather than dividing by 8, use a smaller capacitor so it decays faster, and it'll take less time. I would be extremely surprised if your calculations or servo set functions were taking any human-noticeable time, but you'll know for sure if you measure.

    Jason

    Edit: I'll have to learn to type faster. Beau beat me to it. :)
  • Duane DegnDuane Degn Posts: 10,588
    edited 2014-03-12 16:38
    You might want to take a look at a PASM version of RCTIME. I haven't used it myself yet, but Clock Loop says it works well.
  • minitrueminitrue Posts: 17
    edited 2014-03-12 16:55
    Thanks, guys.

    The code that you suggested, Beau, is not that different than what could be done with a basic stamp. (Don't get me wrong- I love that it works!) but I think the slowness has to do with the fact that all the inputs are checked, one-at-a-time and then all the conversions are done one-at-a-time and then all the servos are given instructions one-at-a-time. I think I would like to try it using 6 different cogs. Each cog would be responsible for a loop of checking one joy stick, doing its own math and then sending that info to a servo. Could multiple cogs running a routine like that work?
  • JasonDorieJasonDorie Posts: 1,930
    edited 2014-03-12 17:17
    I can pretty much guarantee you that's not the case. I wrote my main quadrotor loop in Spin. It's doing significantly more work in the main loop than you are, and exactly the same way - read a bunch of inputs, do a bunch of math, set some servo outputs. It's doing it 250 times per second, and with time left over. (No disrespect intended by the way, so I hope it didn't come across like that)

    Measure the time taken by the RCTime reading loop. I assure you that's your where your issue is. Your code would go much faster if you used an external ADC, but that will be more complicated than just using smaller caps.

    Jason
  • minitrueminitrue Posts: 17
    edited 2014-03-12 17:23
    JasonDorie wrote: »
    I can pretty much guarantee you that's not the case. I wrote my main quadrotor loop in Spin. It's doing significantly more work in the main loop than you are, and exactly the same way - read a bunch of inputs, do a bunch of math, set some servo outputs. It's doing it 250 times per second, and with time left over. (No disrespect intended by the way, so I hope it didn't come across like that)

    Measure the time taken by the RCTime reading loop. I assure you that's your where your issue is. Your code would go much faster if you used an external ADC, but that will be more complicated than just using smaller caps.

    Jason

    Okay. Thanks. I shall try two of my caps in series and see if that fixes things.
  • JasonDorieJasonDorie Posts: 1,930
    edited 2014-03-12 17:37
    Two caps in series will make it take less time. If you could find a 0.01uf cap instead you'd probably be able to remove your /8 completely, and it'd go about 10x faster. The RCTime code is measuring the time it takes to discharge a capacitor, so using smaller caps or lower-value resistors will mean less time spent to discharge, but it will always be variable depending on the values of your pots.

    If use an ADC, it's read digitally, so the time spent getting your inputs will be much more consistent which I'd advise in the long run anyway. There are objects in the OBEX for reading the MCP-3208, and they're available in through-hole versions, so that would be a relatively low-pain way to go.
  • minitrueminitrue Posts: 17
    edited 2014-03-12 18:07
    Just out of curiosity, do any of you think I will have trouble running my 8 servos off of this board with 4 AA's? I see that the port says I can use up to 16 V. Should I put a bigger battery together?
  • minitrueminitrue Posts: 17
    edited 2014-03-12 18:21
    I just tried putting two .1µF caps in series. I did have to change the math to convert the pot signal to a pulsewidth of the right size. Instead of
    "pot/8 -180" the new math is "pot/4 - 180" which makes sense based on the fact the capacitance is now half. I agree that if I switched to a 0.01µF cap I wouldn't need to do any division at all.

    BUT- the cap change did nothing to fix the sluggish response time of the servo to the sticks. If I push the sticks forward, the servo turns, but if I quickly pull the stick back, the servo continues to spin in the first direction for almost a full second and then changes its behavior. It feels like I have to hold a position on the stick long enough for the data to be collected. The other thing I noticed is that if I just tap the stick all the way to one side and then return it to center, the servo will continue to spin for a full second before it stops.

    I know that in Pbasic, you can set counters for how long a servo should go. In this code each servo is controlled by a line like:

    servo.Set(11, rightpot)

    What determines how long that servo is active for?
  • minitrueminitrue Posts: 17
    edited 2014-03-12 18:30
    2014robocrosstry2 - Archive [Date 2014.03.12 Time 21.27].zip

    Okay. Here is a perfect example of my current issue. In this code that I attached here, I try to control two servos. One is on pin 14 and one is on 15. If I run this code, both servos work, but the lag is unbearable. If I don't change the code but unplug either servo, the other one still works and there is no lag at all. Is my lag problem just a power issue??
  • JasonDorieJasonDorie Posts: 1,930
    edited 2014-03-12 18:49
    I just looked at the "Servos" object you're using - it appears to be written in Spin. The servo object I assumed you were using was Servo32, and that's a much different animal. If you're not using any of the ramping features, the Servo32 object will likely be a much better choice for you - It's written almost entirely in PASM. It takes a cog (so does the BOE servo code), but it updates 50 times a second, and does so in parallel.

    The BOE servo code has a loop in it that updates the servos sequentially, which is horrible - That's 1/50th a second per servo in the loop, and there are 14 of them. That's really bad. That's probably your issue. (which I would have discovered sooner if I had actually timed the code, like I suggested you do.. d'oh!)

    I'd suggest trying the Servo32 object that ships with the Propeller IDE. You'll have to call the start method yourself, but I think your Set() commands will end up being the same.
Sign In or Register to comment.