Shop OBEX P1 Docs P2 Docs Learn Events
QuadCopter (Tri/Quad/Hex/Octa) - propeller chip code discussion — Parallax Forums

QuadCopter (Tri/Quad/Hex/Octa) - propeller chip code discussion

Cluso99Cluso99 Posts: 18,069
edited 2012-09-20 19:58 in Propeller 1
I have changed the title because it has evolved more into help from Jason to get me running.

A number of us are playing with QuadCopters (and similar).

I have found that (myself included) many objects vary in the data range that is being passed between objects, requiring unnecessary code conversions.

For example, the servo inputs can be 0+-500 (-500..+500); 0..1000; 1000..2000.
Now, the 1000..2000 is because this is the ms range of each servo; 0..1000 is just the value normalised; and -500..+500 is centred on 0 obviously.

Similar problems for driving the ESCs where ultimately the are converted to 1000..2000 for output (or something else if using I2C ESCs).

Then, we have the various sensors that can give various results.

For those involved with programming their QUads, do you think a standard range value would make sense???
«1

Comments

  • ratronicratronic Posts: 1,451
    edited 2011-12-28 08:06
    I have been following Jason's code and I think he changes the #'s in different parts of the code because they are easier to deal with in that section of the code. I am still trying to find out how he gets a stable lock from the gryo only. I monitored the gryo accumulated variables in his code and they do drift but I am not anywhere near his brillant talent to write these things.
  • Cluso99Cluso99 Posts: 18,069
    edited 2011-12-28 14:23
    I am about to try out Jasons PID code... maybe today if I am lucky.

    I have modified/re-done the ESC & RC drivers (so I could understand how they worked). I have a Wii Motion Plus driver (from Pat Daderko & John Abshier & Jo
  • ratronicratronic Posts: 1,451
    edited 2011-12-28 14:42
    I have already built an Elev-8 but stripped one of the prop adapter shafts so I am grounded until I get replacement parts. Although I have a Hoverfly sport and once I get it flying with that, I have all the parts to make up a board to use with Jason's code. Let us know how it turns out.
  • JasonDorieJasonDorie Posts: 1,930
    edited 2011-12-28 17:25
    The accumulated gyro values certainly do drift, but the drift is on the order of a few degrees per minute. It's remarkably small compared to what I expected. I also account for temperature drift in my gyro code in a way that may need to be altered "per installation" - I haven't checked any other gyros but my own with my temperature drift compensation code.

    I tend to use values of +/- 500 everywhere in my code that deals with ESC / servo values simply because it's easier to do things like scaled mixing, addition, etc. As an example, I read the remote input and it says "go left" (-100). I take that number, multiply it by a scale factor, then add it to the left ESC value and subtract it from the right one. If the value I got from the remote was a PWM length, it'd range from 1000 to 2000, so the math wouldn't work nearly as cleanly.

    At the very last moment before I set the outputs in the ESC/servo code, I add the base 1500 uSec value and clamp them. In fact I'm not sure I even do that - I think because I base everything off the "throttle" value as my starting point for addition / subtraction, I add the 1500 to the throttle value, which has the effect of adding it to all the others. I still have to clamp them individually.

    To clarify, I used to do this: (and I'm ignoring the rudder here)
    Output[LEFT] := Throttle + Aileron + 1500
    Output[RIGHT] := Throttle - Aileron + 1500
    Output[FRONT] := Throttle + Elevator + 1500
    Output[BACK] := Throttle - Elevator + 1500
    Clamp( Outputs, 1000, 2000 )
    

    but it's more efficient (less code) to do this:
    Throttle += 1500
    Output[LEFT] := Throttle + Aileron
    Output[RIGHT] := Throttle - Aileron
    Output[FRONT] := Throttle + Elevator
    Output[BACK] := Throttle - Elevator
    Clamp( Outputs, 1000, 2000 )
    

    All the remote control inputs are centered at 0 with a range of +/- 500, roughly. It tends to be less than that because of the settings in the remote transmitter - Usually about +/- 400 or a little better.

    Regarding standard ranges for things, it might make some things simpler, and others harder. I try to work within the ranges that I get from my sensors for the PIDs, for example. The PIDs just take a measured value and a desired one, and produce an output from that and some constants. If the constants are set properly, the range conversion happens as a side effect, so it doesn't need to be done elsewhere.

    Most quad code I've seen, for example, converts the gyro readings into degrees per second values by scaling them from "gyro units" to degrees, and then scaling by the time step between readings. This makes the numbers much easier for people to digest, but the quad doesn't care if it's degrees or some other units *unless* you're using standard library functions like sin, cos, etc where it becomes necessary. Atan2, the function used most of the time, doesn't care what the inputs are - they're vector coordinates.

    The other caveat of converting to a standard range is that you may lose precision. My accumulated gyro readings end up being about 320,000 units per 90 degrees, or a little over 1.2 million units per full revolution. If you choose a lower range as a standard, you may sacrifice some of the control nuance you get by having so much precision kept internally. I can't say for sure that would *actually* happen because I haven't tried using lower ranges - I figured keeping the most precision possible would ultimately be a good thing, so I stuck with that. It's certainly possible that I don't need anywhere near the precision I have.
  • Cluso99Cluso99 Posts: 18,069
    edited 2011-12-28 20:59
    Thanks Jason.

    I have been playing with the gyro and accel outputs today from the Wii. I wasn't certain that I was getting anything valid so I started a crude graph using PST and dashes, and scaling it. I think I may be getting correct and usable values now???

    If I take the pcb, and roll it 45 degrees it seems the gyros settle quite quickly (few seconds). Is this mormal? Maybe because I am displaying my outputs between reads I am losing what I expected to see.
  • JasonDorieJasonDorie Posts: 1,930
    edited 2011-12-28 22:32
    The gyros only measure angular rate, not angular value, so the moment the sensor isn't rotating you'll get zeros out of it again. If that's what you're seeing, then yes, that's normal.

    In order to get an estimate of your orientation, you need to accumulate the samples and display the sum over time. If your gyro rotates left, then right, the sum of those rotations should be zero. You'll have a little drift and sample imprecision in there too, but it should be close to a net zero.


    The accelerometer produces a value that, on average, will represent gravity, so those shouldn't settle back to zero like the gyro does, but they'll be much noisier.

    If you want, you can download my GroundStation program - The packet format is -really- simple, and only 8 bytes total:

    $7F7F = gyro packet
    WORD = GX
    WORD = GY
    WORD = GZ

    The word values are 16 bit, signed, raw gyro readings, and it will graph them for you, complete with min, max, average, and variance numbers for the current set of displayed values. It auto-ranges the graph, too. The 7F7F value is rare enough that it allows me to re-sync mid stream. It runs at 115,200 baud and grabs the first valid serial port past COM4 it can find, assuming that's your PropPlug. There's no reason you couldn't make your program send out accelerometer values (or any other three values) instead - it'll just as happily graph those.

    Because the sent data is only 8 bytes, and it's raw, you won't fill the TX buffer so the code runs pretty quick. On the prop side I use:
        'Send gyro readings at the end of frame
        dbg.tx( $7f )
        dbg.tx( $7f )
        dbg.tx( gx >> 8 )
        dbg.tx( gx )
        dbg.tx( gy >> 8 )
        dbg.tx( gy )
        dbg.tx( gz >> 8 )
        dbg.tx( gz )
    

    Jason
  • Cluso99Cluso99 Posts: 18,069
    edited 2011-12-29 00:35
    Thanks heaps Jason. I thought I was going nuts because I got consistent results from the gyro. Guess I should have read more about the gyro output! My accel os doing what you say too. So looking good.

    So maybe I can get this off the ground tomorrow now :)
  • ratronicratronic Posts: 1,451
    edited 2011-12-29 08:03
    Jason or Cluso99 I had bought an IMU from spark fun that has both the ITG3200 gyro and the ADXL345 accellerometer. I had to change the address for the gyro from $D2 to $D0 as that is how it is hard wired. My problem with using this board with Jasons ITG-3200-pasm.spin code is if it reads both the accellerometer and the gyro at the same time I get trash back. If I comment out one of the calls to read the the accellerometer or gyro the ouput cleans up. WHAT I would like to know is I am getting back gyro readings that flucuate less than about +/- 10 when sitting still. All kinds of output when moved. Is this about what you guys are getting?
  • JasonDorieJasonDorie Posts: 1,930
    edited 2011-12-29 09:34
    Dave: that is exactly what you should see.

    Someone posted in the DCM thread that I'm missing a read termination call in the PASM code (he details the changes). I haven't fixed it on my side yet, so that's likely what's causing your issue with all the reads enabled.
  • ratronicratronic Posts: 1,451
    edited 2011-12-29 11:35
    Thanks Jason for all of your explanations.
  • Cluso99Cluso99 Posts: 18,069
    edited 2011-12-29 15:38
    Dave, that is what I see too. It is really just the last 3 bits in the 14bit result.
    Thought today was going to be the day...but a friend from NZ is coming so guess I will not be attempting my flying code today.
  • ratronicratronic Posts: 1,451
    edited 2011-12-29 16:32
    Clusso99 I do want to try his code on the Elev-8 and after he pointed out the possible problems and I corrected them with using the IMU I have, now I am getting about +/- 1 to 5 depending on the axis. Still would like to know how your results turn out when you get the chance.
  • JasonDorieJasonDorie Posts: 1,930
    edited 2011-12-29 16:43
    +/- 5 is excellent - I think that's as low as mine have ever gone. It was flyable with quite a bit worse than that. Once your motors start going those numbers will jump quite a bit because of vibration.

    You may also want to check the temperature drift by pointing a hair dryer at your board - if the gyro numbers change quite a bit as the temp goes up you might need to alter my formula to compensate for it.
  • JasonDorieJasonDorie Posts: 1,930
    edited 2011-12-29 16:46
    I have an Elev-8 kit here too. Once I get it assembled I'm going to make a version of my code specifically for it. Most of the changes are simple pin assignments, but the servo output loop will be a little more involved. Shouldn't take long though.
  • ratronicratronic Posts: 1,451
    edited 2011-12-29 17:37
    That is totally cool Jason! Now I have the IMU working I am trying it out with your DCM visualizer. It will take me a while to figure out how to change the axis in your DCM prop code but it is working just the box on the screen is out of alignment of this IMU. You said you do this stuff for work, I am really glad you are sharing your knowledge with us.
  • JasonDorieJasonDorie Posts: 1,930
    edited 2011-12-29 18:14
    If you can tell me how your sensor axis are aligned I might be able to suggest the changes needed (or at least point you to what you need to change). I don't do exactly this stuff for work (I write game code and tools for sports video games) but the math I use at work has a lot of commonality with this stuff. You're very welcome. :)
  • ratronicratronic Posts: 1,451
    edited 2011-12-29 18:33
    The IMU I am using is this. The section of code I think I need to correct the alignment of the screen box to this IMU is
    PUB UpdateLoop | iGx, iGy, iGz, ErrorAxis[3]                                                       
                                                                                                       
      'Convert the gyro readings into proper range for the DCM inputs.  Also, swap the axis            
      'around and adjust signs to coincide with my frame of reference                                  
      iGz := -Gx / 5                                                                                   
      iGx :=  Gy / 5                                                                                   
      iGy := -Gz / 5                                                                                   
    
    How far off am I?
  • JasonDorieJasonDorie Posts: 1,930
    edited 2011-12-29 19:37
    That's the spot. Chances are all you'll have to do is this:
      iGx := Gx / 5
      iGz := Gy / 5
      iGy := Gz / 5
    

    I swap Y & Z from the gyro/accel because I think of Y as down and Z as forward (standard convention in games) whereas the gyro/accel combo treats Z as down and Y as forward. You may or may not need to leave the negations in there.
  • ratronicratronic Posts: 1,451
    edited 2011-12-29 20:15
    Yep that worked. Amazing program but the spin and C# math codes have my head "spinning".
  • JasonDorieJasonDorie Posts: 1,930
    edited 2011-12-29 20:22
    It took a while for it to sink in for me too - I had to read the DCM paper about 15 times or so (no joke) and it started to make sense. There is at least one part that I still consider "magic" because I don't get *why* it works the way it does, but I finally understand the rest of it.
  • Cluso99Cluso99 Posts: 18,069
    edited 2011-12-30 19:09
    Jason:

    After some fiddling around... The Wii alternates between the gyro and the accel results, so I have to check and reissue the read command if its not the right one (because I am ignoring the accel for now, but it is wired). The other factor is that the gyro results can be scaled by *2000/440 if a fast move is detected. So, this is close enough (for now anyways) to 4.5 so I just *4 (shl 2) and then do a /2 (shr) and add them together... nice and quick maths.

    Anyway, here is my code - you may recognise some of it :)
    PRI FlightLoop
    ''calculate and update controls every 200Hz
      'initialise
      Gyro_FindZero                                         'find GX0/GY0/GZ0 over 1s
      DisplayGyroZero
      
      'setup PID scales
      RollPID.Init ( 65, 0, 10 )
      PitchPID.Init( 65, 0, 10 )
      YawPID.Init  ( 65, 0, 10 )
      
      loopfreq := clkfreq / 200                             'precalc 200Hz loop value to speedup code
      lastcnt := cnt
    ''========== Flight Loop ==========
      repeat
    {----------  
        'read RC Receiver
        Thro := rcin.get(0)                                 'read throttle
        Aile := rcin.get(1)                                 'read aileron
        Elev := rcin.get(2)                                 'read elevator
        Rudd := rcin.get(3)                                 'read rudder
    ----------}
        Thro := 1500                '<=== fix values
        Aile := 1500
        Elev := 1500
        Rudd := 1500
        'now limit throttle/aileron/elevator/rudder
        Thro := 1000 #> Thro <# 2000                        'limit between 1ms..2ms
        Aile := 1000 #> Aile <# 2000                        'limit between 1ms..2ms
        Elev := 1000 #> Elev <# 2000                        'limit between 1ms..2ms
        Rudd := 1000 #> Rudd <# 2000                        'limit between 1ms..2ms
        'make code friendly +/-0
        Thro -=1500
        Aile -=1500
        Elev -=1500
        Rudd -=1500
        'calc desired throttle mix
        ThroMix := (Thro + 400) ~> 2                        'approx 0-256
        ThroMix := 0 #> ThroMix #> 64                       'clamp throttlemix to 1/4 max
        'accum integral for Aile/Elev/Rudd
        iAile += Aile
        iElev += Elev
        iRudd += Rudd
        'read gyro x,y&z
        repeat
          gyro.readMotionPlus                                 'read data from MotionPlus
        while gyro.datatype <> 
        GX := gyro.gyrox - GX0                              'adj for zero state
        GY := gyro.gyroy - GY0
        GZ := gyro.gyroz - GZ0     
        'accum integral for gyro X/Y/Z
        iGX += GX
        iGY += GY
        iGZ += GZ
        'calc desired Roll/Pitch/Yaw
        DesiredRoll  := iAile << 1
        DesiredPitch := iElev << 1
        DesiredYaw   := iRudd << 1
        'calc PID values
        RollOut  := RollPID.calculate ( DesiredRoll,  iGX )
        PitchOut := PitchPID.calculate( DesiredPitch, iGY )
        YawOut   := YawPID.calculate  ( DesiredYaw,   iGZ )
        'calculate ESC output values
        ThroMix += 1500                                     'make "servo friendly" again
        eFront := Thro + ((-PitchOut + YawOut) * ThroMix) ~> 6
        eRight := Thro + (( RollOut  - YawOut) * ThroMix) ~> 6
        eBack  := Thro + (( PitchOut + YawOut) * ThroMix) ~> 6
        eLeft  := Thro + ((-RollOut  - YawOut) * ThroMix) ~> 6
    {{
        'and limit values
        eFront := 1000 #> eFront <# 2000
        eRight := 1000 #> eRight <# 2000
        eBack  := 1000 #> eBack  <# 2000
        eLeft  := 1000 #> eLeft  <# 2000
    }}
    {{
        'output throttle to all 4 motors (ESCs) 
        rcout.out(eFront,0)                                 ' & output to Esc0
        rcout.out(eRight,1)                                 ' & output to Esc1        
        rcout.out(eBack, 2)                                 ' & output to Esc2        
        rcout.out(eLeft, 3)                                 ' & output to Esc3        
    }}
        DisplayEsc                                             'display the values
    '    waitcnt(loopfreq + lastcnt)                         ' 200Hz loop   
        waitcnt(clkfreq/10 + cnt)
        lastcnt := cnt                                      'save for next loop time
    
    

    Postedit: The GX, GY & GZ values displayed have 1500 added to each (keeps display better organised)!

    I am using your older PID routine. However, I am not getting what I expect.
    I am seeing gyro values 1500 +- 30 for x,y&z but the escs are setting 50us, -250us, 325us, -150us all +- 25us or 50us.
    My gyro pcb is sitting on the bench fairly flat and definately still. I have fixed RC inputs of 1500 ea (in code).

    Do you have any pointers on what is wrong??? I am just about to display the other readings and calcs.

    Here is my debug output
    Cluso's QuadCopter (4 channels) v0.07x
    Gyro Zero GX=7930 GY=7604 GZ=8190
      GX=1549 GY=1519 GZ=1522 Throttle -25us, -75us, 125us, -25us.
      GX=1518 GY=1525 GZ=1507 Throttle 25us, -75us, 50us, 0us.
      GX=1540 GY=1522 GZ=1502 Throttle 25us, -75us, 75us, -25us.
      GX=1521 GY=1527 GZ=1514 Throttle 25us, -75us, 75us, -25us.
      GX=1527 GY=1534 GZ=1509 Throttle 25us, -75us, 75us, -25us.
      GX=1535 GY=1513 GZ=1507 Throttle 0us, -50us, 75us, -25us.
      GX=1528 GY=1518 GZ=1518 Throttle 0us, -50us, 75us, -25us.
      GX=1538 GY=1523 GZ=1510 Throttle 25us, -75us, 75us, -25us.
      GX=1523 GY=1533 GZ=1515 Throttle 25us, -75us, 75us, -25us.
      GX=1532 GY=1522 GZ=1508 Throttle 25us, -75us, 75us, -25us.
      GX=1532 GY=1523 GZ=1508 Throttle 25us, -75us, 75us, -25us.
      GX=1528 GY=1533 GZ=1510 Throttle 25us, -75us, 75us, -25us.
      GX=1529 GY=1513 GZ=1506 Throttle 25us, -75us, 75us, -25us.
      GX=1510 GY=1547 GZ=1502 Throttle 50us, -100us, 50us, 0us.
      GX=1552 GY=1504 GZ=1518 Throttle 0us, -50us, 100us, -50us.
      GX=1521 GY=1529 GZ=1515 Throttle 25us, -75us, 75us, -25us.
      GX=1540 GY=1517 GZ=1498 Throttle 25us, -75us, 100us, -50us.
      GX=1552 GY=1513 GZ=1513 Throttle 25us, -75us, 100us, -50us.
      GX=1535 GY=1538 GZ=1506 Throttle 25us, -75us, 100us, -50us.
      GX=1547 GY=1521 GZ=1510 Throttle 25us, -75us, 100us, -50us.
      GX=1513 GY=1547 GZ=1509 Throttle 50us, -100us, 75us, -25us.
      GX=1539 GY=1501 GZ=1504 Throttle 0us, -50us, 100us, -50us.
      GX=1513 GY=1535 GZ=1504 Throttle 50us, -100us, 75us, -25us.
      GX=1521 GY=1525 GZ=1514 Throttle 25us, -75us, 75us, -25us.
      GX=1532 GY=1529 GZ=1518 Throttle 25us, -75us, 100us, -50us.
      GX=1521 GY=1535 GZ=1518 Throttle 25us, -125us, 100us, 0us.
      GX=1533 GY=1535 GZ=1512 Throttle 50us, -100us, 100us, -50us.
      GX=1537 GY=1516 GZ=1515 Throttle 0us, -100us, 125us, -25us.
      GX=1529 GY=1526 GZ=1516 Throttle 0us, -100us, 125us, -25us.
      GX=1546 GY=1521 GZ=1515 Throttle 0us, -100us, 125us, -25us.
      GX=1523 GY=1536 GZ=1514 Throttle 25us, -125us, 100us, 0us.
      GX=1530 GY=1517 GZ=1509 Throttle 25us, -75us, 100us, -50us.
      GX=1522 GY=1528 GZ=1502 Throttle 50us, -100us, 75us, -25us.
      GX=1539 GY=1525 GZ=1518 Throttle 0us, -100us, 125us, -25us.
      GX=1522 GY=1527 GZ=1510 Throttle 50us, -100us, 100us, -50us.
      GX=1524 GY=1529 GZ=1507 Throttle 50us, -100us, 100us, -50us.
      GX=1526 GY=1524 GZ=1516 Throttle 0us, -100us, 125us, -25us.
      GX=1533 GY=1523 GZ=1508 Throttle 25us, -75us, 100us, -50us. 
    

    ratronic: This output may help you too. The GX, GY & GZ are the values read from the gyro after the zero values are subtracted.
  • Cluso99Cluso99 Posts: 18,069
    edited 2011-12-30 19:41
    Disregard the code and output in the previous post. Here is an update...


    Looks much better now :) Looks like my zeroing is not quite correct so I have a slight scew in my motors (theory, no motors running nor rc connected)
    PRI FlightLoop
    ''calculate and update controls every 200Hz
      'initialise
      Gyro_FindZero                                         'find GX0/GY0/GZ0 over 1s
      DisplayGyroZero
      
      'setup PID scales
      RollPID.Init ( 65, 0, 10 )
      PitchPID.Init( 65, 0, 10 )
      YawPID.Init  ( 65, 0, 10 )
      
      loopfreq := clkfreq / 200                             'precalc 200Hz loop value to speedup code
      lastcnt := cnt
    ''========== Flight Loop ==========
      repeat
    {----------  
        'read RC Receiver
        Thro := rcin.get(0)                                 'read throttle
        Aile := rcin.get(1)                                 'read aileron
        Elev := rcin.get(2)                                 'read elevator
        Rudd := rcin.get(3)                                 'read rudder
    ----------}
        Thro := 1500                '<=== fix values
        Aile := 1500
        Elev := 1500
        Rudd := 1500
        'now limit throttle/aileron/elevator/rudder
        Thro := 1000 #> Thro <# 2000                        'limit between 1ms..2ms
        Aile := 1000 #> Aile <# 2000                        'limit between 1ms..2ms
        Elev := 1000 #> Elev <# 2000                        'limit between 1ms..2ms
        Rudd := 1000 #> Rudd <# 2000                        'limit between 1ms..2ms
        'make code friendly +/-0
        Thro -=1500
        Aile -=1500
        Elev -=1500
        Rudd -=1500
        'calc desired throttle mix
        ThroMix := (Thro + 400) ~> 2                        'approx 0-256
        ThroMix := 0 #> ThroMix #> 64                       'clamp throttlemix to 1/4 max
        'accum integral for Aile/Elev/Rudd
        iAile += Aile
        iElev += Elev
        iRudd += Rudd
        'read gyro x,y&z
        repeat
          gyro.readMotionPlus                                 'read data from MotionPlus
        while gyro.datatype <> %10
        GX := gyro.gyrox - GX0                              'adj for zero state
        GY := gyro.gyroy - GY0
        GZ := gyro.gyroz - GZ0     
        'accum integral for gyro X/Y/Z
        iGX += GX
        iGY += GY
        iGZ += GZ
        'calc desired Roll/Pitch/Yaw
        DesiredRoll  := iAile << 1
        DesiredPitch := iElev << 1
        DesiredYaw   := iRudd << 1
        'calc PID values
        RollOut  := RollPID.calculate ( DesiredRoll,  iGX )
        PitchOut := PitchPID.calculate( DesiredPitch, iGY )
        YawOut   := YawPID.calculate  ( DesiredYaw,   iGZ )
        'calculate ESC output values
        Thro += 1500                                     'make "servo friendly" again
        eFront := Thro + ((-PitchOut + YawOut) * ThroMix) ~> 6
        eRight := Thro + (( RollOut  - YawOut) * ThroMix) ~> 6
        eBack  := Thro + (( PitchOut + YawOut) * ThroMix) ~> 6
        eLeft  := Thro + ((-RollOut  - YawOut) * ThroMix) ~> 6
    {{
        'and limit values
        eFront := 1000 #> eFront <# 2000
        eRight := 1000 #> eRight <# 2000
        eBack  := 1000 #> eBack  <# 2000
        eLeft  := 1000 #> eLeft  <# 2000
    }}
    {{
        'output throttle to all 4 motors (ESCs) 
        rcout.out(eFront,0)                                 ' & output to Esc0
        rcout.out(eRight,1)                                 ' & output to Esc1        
        rcout.out(eBack, 2)                                 ' & output to Esc2        
        rcout.out(eLeft, 3)                                 ' & output to Esc3        
    }}
        DisplayEsc                                             'display the values
    '    waitcnt(loopfreq + lastcnt)                         ' 200Hz loop   
        waitcnt(clkfreq/10 + cnt)
        lastcnt := cnt                                      'save for next loop time
    
    

    In the following outputs, the gyros and Escs are converted to 1000-2000 range with 1500 being the center.
    Cluso's QuadCopter (4 channels) v0.07x
    Gyro Zero GX=7932 GY=7608 GZ=8190
     G-XYZ=1569 1475 1510 T/Mix=100 Desired=0 0 0 Esc= 1498, 1498, 1506, 1496.
     G-XYZ=1513 1549 1514 T/Mix=100 Desired=0 0 0 Esc= 1503, 1493, 1503, 1500.
     G-XYZ=1532 1512 1506 T/Mix=100 Desired=0 0 0 Esc= 1500, 1496, 1504, 1498.
     G-XYZ=1527 1534 1504 T/Mix=100 Desired=0 0 0 Esc= 1501, 1495, 1504, 1498.
     G-XYZ=1523 1525 1502 T/Mix=100 Desired=0 0 0 Esc= 1501, 1495, 1504, 1498.
     G-XYZ=1534 1519 1498 T/Mix=100 Desired=0 0 0 Esc= 1500, 1496, 1504, 1498.
     G-XYZ=1525 1526 1506 T/Mix=100 Desired=0 0 0 Esc= 1501, 1495, 1504, 1498.
     G-XYZ=1530 1515 1509 T/Mix=100 Desired=0 0 0 Esc= 1500, 1496, 1504, 1498.
     G-XYZ=1536 1526 1515 T/Mix=100 Desired=0 0 0 Esc= 1501, 1495, 1504, 1498.
     G-XYZ=1525 1523 1506 T/Mix=100 Desired=0 0 0 Esc= 1501, 1495, 1504, 1498.
     G-XYZ=1527 1519 1512 T/Mix=100 Desired=0 0 0 Esc= 1500, 1496, 1504, 1498.
     G-XYZ=1527 1517 1509 T/Mix=100 Desired=0 0 0 Esc= 1500, 1496, 1504, 1498.
     G-XYZ=1536 1523 1504 T/Mix=100 Desired=0 0 0 Esc= 1501, 1495, 1504, 1498.
     G-XYZ=1518 1527 1510 T/Mix=100 Desired=0 0 0 Esc= 1501, 1495, 1504, 1498.
     G-XYZ=1531 1523 1510 T/Mix=100 Desired=0 0 0 Esc= 1501, 1495, 1504, 1498.
     G-XYZ=1528 1520 1515 T/Mix=100 Desired=0 0 0 Esc= 1501, 1495, 1504, 1498.
     G-XYZ=1527 1533 1510 T/Mix=100 Desired=0 0 0 Esc= 1501, 1495, 1504, 1498.
     G-XYZ=1523 1522 1507 T/Mix=100 Desired=0 0 0 Esc= 1501, 1495, 1504, 1498.
     G-XYZ=1523 1525 1514 T/Mix=100 Desired=0 0 0 Esc= 1501, 1495, 1504, 1498.
     G-XYZ=1526 1520 1516 T/Mix=100 Desired=0 0 0 Esc= 1501, 1495, 1504, 1498.
     G-XYZ=1517 1528 1514 T/Mix=100 Desired=0 0 0 Esc= 1501, 1495, 1504, 1498.
     G-XYZ=1536 1531 1510 T/Mix=100 Desired=0 0 0 Esc= 1501, 1495, 1506, 1496.
     G-XYZ=1526 1530 1519 T/Mix=100 Desired=0 0 0 Esc= 1501, 1495, 1504, 1498.
     G-XYZ=1538 1536 1506 T/Mix=100 Desired=0 0 0 Esc= 1503, 1493, 1506, 1496.
     G-XYZ=1521 1529 1507 T/Mix=100 Desired=0 0 0 Esc= 1501, 1495, 1504, 1498.
     G-XYZ=1536 1523 1510 T/Mix=100 Desired=0 0 0 Esc= 1501, 1495, 1506, 1496.
     G-XYZ=1533 1524 1509 T/Mix=100 Desired=0 0 0 Esc= 1501, 1495, 1506, 1496.
     G-XYZ=1537 1519 1517 T/Mix=100 Desired=0 0 0 Esc= 1500, 1493, 1507, 1498.
     G-XYZ=1519 1529 1509 T/Mix=100 Desired=0 0 0 Esc= 1501, 1495, 1504, 1498.
     G-XYZ=1533 1523 1514 T/Mix=100 Desired=0 0 0 Esc= 1500, 1493, 1507, 1498.
     G-XYZ=1527 1530 1506 T/Mix=100 Desired=0 0 0 Esc= 1501, 1495, 1506, 1496.
     G-XYZ=1536 1526 1506 T/Mix=100 Desired=0 0 0 Esc= 1501, 1495, 1506, 1496.
     G-XYZ=1529 1526 1503 T/Mix=100 Desired=0 0 0 Esc= 1503, 1493, 1506, 1496.
     G-XYZ=1530 1517 1514 T/Mix=100 Desired=0 0 0 Esc= 1500, 1493, 1507, 1498.
     G-XYZ=1528 1517 1510 T/Mix=100 Desired=0 0 0 Esc= 1501, 1495, 1506, 1496.
     G-XYZ=1535 1528 1517 T/Mix=100 Desired=0 0 0 Esc= 1501, 1492, 1507, 1498.
     G-XYZ=1523 1532 1512 T/Mix=100 Desired=0 0 0 Esc= 1503, 1493, 1506, 1496.
    
  • JasonDorieJasonDorie Posts: 1,930
    edited 2011-12-30 19:49
    I was just about to say - you added the 1500 offset to the ThroMix value, not the Throttle. :)

    In case it's not clear, that ThroMix value is just used a scale to apply to the mixing code so that a non-throttle stick input when it's at rest won't start the motors spinning. I smoothly mix the balance code back in over a very short throttle range that wouldn't be useful in flight anyway. It'd be easy enough to make it just switch on/off instead, but this seemed cleaner.

    I like your limiting code - I was pretty sure those could be done on one line, but wasn't sure how. I may have to adopt that.

    IE:
    eFront := 1000 #> eFront <# 2000

    I'll time them to see which is faster, but yours looks like it'd be fewer ops.
  • Cluso99Cluso99 Posts: 18,069
    edited 2011-12-30 20:24
    Here are outputs by moving the gyro...
    [U][I]PITCH...
    [/I][/U]G-XYZ=1457 1721 1604 T/Mix=100 Desired=0 0 0 Esc= 1506, 1478, 1506, 1509.
     G-XYZ=1344 1607 1597 T/Mix=100 Desired=0 0 0 Esc= 1500, 1484, 1498, 1517.
     G-XYZ=1492 1496 1503 T/Mix=100 Desired=0 0 0 Esc= 1500, 1496, 1501, 1501.
     G-XYZ=1365 1529 1253 T/Mix=100 Desired=0 0 0 Esc= 1517, 1510, 1478, 1493.
     G-XYZ=1633 2915 1446 T/Mix=100 Desired=0 0 0 Esc= 1593, 1412, 1506, 1487.
     G-XYZ=1414 3631 1423 T/Mix=100 Desired=0 0 0 Esc= 1642, 1367, 1490, 1500.
     G-XYZ=1856 3487 1320 T/Mix=100 Desired=0 0 0 Esc= 1642, 1379, 1512, 1465.
     G-XYZ=1233 1998 1336 T/Mix=100 Desired=0 0 0 Esc= 1550, 1468, 1475, 1506.
     G-XYZ=1466 1292 1495 T/Mix=100 Desired=0 0 0 Esc= 1498, 1501, 1498, 1501.
     G-XYZ=1246 -883 1677 T/Mix=100 Desired=0 0 0 Esc= 1350, 1628, 1495, 1526.
     G-XYZ=1462 -1886 2081 T/Mix=100 Desired=0 0 0 Esc= 1259, 1668, 1534, 1537.
     G-XYZ=1504 1485 1497 T/Mix=100 Desired=0 0 0 Esc= 1498, 1498, 1501, 1501.
     G-XYZ=1517 1486 1519 T/Mix=100 Desired=0 0 0 Esc= 1498, 1498, 1503, 1500.
     G-XYZ=1461 1511 1532 T/Mix=100 Desired=0 0 0 Esc= 1498, 1495, 1500, 1506.
     ------------------------------------------------------------------------------------------------------
    [I][U]PITCH (and perhaps some Roll)...
    [/U][/I]G-XYZ=1503 1479 1507 T/Mix=100 Desired=0 0 0 Esc= 1498, 1498, 1501, 1501.
     G-XYZ=1434 1492 1573 T/Mix=100 Desired=0 0 0 Esc= 1495, 1492, 1501, 1510.
     G-XYZ=1449 1511 1527 T/Mix=100 Desired=0 0 0 Esc= 1498, 1495, 1500, 1506.
     G-XYZ=1470 1519 1479 T/Mix=100 Desired=0 0 0 Esc= 1503, 1496, 1498, 1501.
     G-XYZ=1604 1517 1863 T/Mix=100 Desired=0 0 0 Esc= 1479, 1473, 1529, 1517.
     G-XYZ=4038 1570 1316 T/Mix=100 Desired=0 0 0 Esc= 1515, 1503, 1650, 1331.
     G-XYZ=3474 1316 1900 T/Mix=100 Desired=0 0 0 Esc= 1464, 1482, 1654, 1398.
     G-XYZ=3219 842 1454 T/Mix=100 Desired=0 0 0 Esc= 1460, 1539, 1614, 1385.
     G-XYZ=1800 897 1804 T/Mix=100 Desired=0 0 0 Esc= 1440, 1515, 1550, 1493.
     G-XYZ=1370 1430 1443 T/Mix=100 Desired=0 0 0 Esc= 1495, 1504, 1501, 1498.
     G-XYZ=1148 1570 1443 T/Mix=100 Desired=0 0 0 Esc= 1503, 1496, 1487, 1512.
     G-XYZ=-608 1684 1684 T/Mix=100 Desired=0 0 0 Esc= 1496, 1475, 1392, 1635.
     G-XYZ=-80 1684 1260 T/Mix=100 Desired=0 0 0 Esc= 1523, 1501, 1395, 1579.
     G-XYZ=691 1123 1234 T/Mix=100 Desired=0 0 0 Esc= 1490, 1537, 1439, 1532.
     G-XYZ=1498 1509 1491 T/Mix=100 Desired=0 0 0 Esc= 1498, 1498, 1503, 1500.
     G-XYZ=1534 1486 1500 T/Mix=100 Desired=0 0 0 Esc= 1495, 1498, 1507, 1498.
    --------------------------------------------------------------------
    [U][I]YAW (maybe a bit violent)...
    [/I][/U]G-XYZ=1520 1485 1498 T/Mix=100 Desired=0 0 0 Esc= 1496, 1500, 1506, 1496.
     G-XYZ=1493 1489 1509 T/Mix=100 Desired=0 0 0 Esc= 1495, 1498, 1504, 1501.
     G-XYZ=1536 1494 2074 T/Mix=100 Desired=0 0 0 Esc= 1460, 1464, 1542, 1532.
     G-XYZ=1891 1303 4076 T/Mix=100 Desired=0 0 0 Esc= 1323, 1348, 1690, 1637.
     G-XYZ=1862 1854 5020 T/Mix=100 Desired=0 0 0 Esc= 1293, 1250, 1754, 1701.
     G-XYZ=966 1748 1499 T/Mix=100 Desired=0 0 0 Esc= 1503, 1471, 1482, 1542.
     G-XYZ=1261 1549 1746 T/Mix=100 Desired=0 0 0 Esc= 1475, 1468, 1515, 1540.
     G-XYZ=1363 1712 435 T/Mix=100 Desired=0 0 0 Esc= 1568, 1540, 1439, 1451.
     G-XYZ=2274 -295 -5973 T/Mix=100 Desired=0 0 0 Esc= 1843, 2068, 1095, 992.
     G-XYZ=1619 1351 1876 T/Mix=100 Desired=0 0 0 Esc= 1464, 1489, 1534, 1512.
     G-XYZ=1305 1651 2133 T/Mix=100 Desired=0 0 0 Esc= 1467, 1454, 1531, 1546.
     G-XYZ=2040 713 1641 T/Mix=100 Desired=0 0 0 Esc= 1437, 1540, 1548, 1473.
     G-XYZ=1426 1653 1499 T/Mix=100 Desired=0 0 0 Esc= 1504, 1492, 1501, 1501.
     G-XYZ=1541 1450 1494 T/Mix=100 Desired=0 0 0 Esc= 1492, 1504, 1507, 1495.
     G-XYZ=1473 1529 1505 T/Mix=100 Desired=0 0 0 Esc= 1496, 1500, 1504, 1498.
     G-XYZ=1506 1500 1491 T/Mix=100 Desired=0 0 0 Esc= 1495, 1501, 1506, 1496.
    

    Now to pluck up the courage to give it a real try...
  • Cluso99Cluso99 Posts: 18,069
    edited 2011-12-30 20:30
    Yes, thats what I had done. (ThroMix instead of Throttle)

    The code in 1 line should be quite a bit quicker. The maths is where I improved the faster spin interpreter quite substantially, so maybe I should give that a run later. Actually, I hate using those types of shortcuts ( ~>, #>) and even +=, -= but unless the compiler is smart, the code will not be reduced as much as it could be.

    Off to have a New Years Eve drink and then try out the code. For Ken... I will try and avoid the cars!
  • JasonDorieJasonDorie Posts: 1,930
    edited 2011-12-30 20:38
    Before actually trying to fly it, I'd recommend holding it firmly and spinning up the props until it's just about holding itself up. The first thing to look for is that your PID outputs are of the correct sign. If they're not, it'll amplify any error instead of correcting it. Once you've determined those are working (roll, pitch, and yaw), then try moving it a little in a direction and see how much it resists, and if it oscillates. Then make sure your stick inputs are also being mixed in properly and have the correct signs.

    Once you've gotten past the "at arms length" tests, then go try it outside. I've had a few cases where I did the latter first and wound up with an upside down quad and a busted prop because I did something silly in the code.
  • Cluso99Cluso99 Posts: 18,069
    edited 2011-12-30 21:57
    Jason: I did try it indoors and there were a few minor issues. I had restricted the escs to 1600. I took it outside, but not to actually fly - just more space.

    I could only get 3 motors to spin (its not the motor or esc because I could reverse them. So yes there is something wrong in the code even though it looked reasonable on the bench. Back to the bench and remove the props to sort it out. At least here I can see the output on the pc.

    But this is actually good because its the first time I have used the gyro data with the motors and there is feedback because I can move the stick and see the responses.

    Suppose I best do the right thing and give this a miss till tomorrow. Its 1645 here on 31Dec. New Years only 7 1/4 hrs away ;)

    Here are two photos of my setup and electronics (sorry they are a bit out of focus)
    Quad014.jpg
    Quad015.jpg
    1024 x 768 - 132K
    1024 x 768 - 80K
  • A. ESERA. ESER Posts: 24
    edited 2012-01-05 06:06
    Hi all,
    I am also working on quadcopter control quite while.
    Previously, I have used IDG500 and IXZ500 gyros and ADXL335 Accelerometer. And I had some success http://vimeo.com/23909597
    But it was not stable as much as I want.
    After I saw Jasons quad, (I think its a great success), I am planning to use ITG3200 and ADXL345 (http://www.sparkfun.com/products/10724)

    @Jason
    I am planning to use your driver for ITG3200 and ADXL345. You have included CORDIC Atan function, what is the format for ARX and ARY ?
    Please help

    @Cluso
    Is there any news from your flight test ?

    Aydin
  • JasonDorieJasonDorie Posts: 1,930
    edited 2012-01-05 12:46
    Aydin,

    I think they are 32 bit full range values, meaning 1^32 = 360 degrees. I never ended up using those values anyway - My DCM version of the flight code uses the gyro and accelerometer values directly, then uses ATan2 and ASin from a modified Float32 object to compute angles from the orientation matrix.

    If you want something that is self-leveling, I have code that works, but I crashed while doing some testing (I did something stupid). I need to build another setup to finish doing the tuning, but it shouldn't take very long - possibly another week or two. It uses the same ITG/ADXL object, so if you're using those chips it will likely drop right in.
  • ratronicratronic Posts: 1,451
    edited 2012-01-05 12:54
    I am and I look forward to your code.
    Edit: I have been playing with your Kalman manager and an IMU that has both of these chips although I really don't have a clue what I'm messing with. But I have experimented with the QAngle, QGryo, and RAngle values and wonder how you even go about calculating those.
Sign In or Register to comment.