Using a Parallex 360° with Arduino

Hi Steve

Thanks for our answer!

To be honest, we tried to rewrite a code we found on the Parallax website, which is in c, in the Arduino environment.

This is the code we used.

/*
  Feedback 360 Angle Control [Low Level Example].c
  
  This is a simplified example of how the low-level position control is done.
  These features would normally be tucked away in a library like abdrive360
  or servo360 with functions to request measured angle, set target angle, 
  and etc.  
*/

// Library inlcudes  
#include "simpletools.h"                      // For pulse_in, print, scan etc...
#include "servo.h"                            // For servo pulse control

int pinFeedback = 14;                         // P14 connected to feedback line
int pinControl = 12;                          // P12 connected to control line

volatile int angle, targetAngle;              // Global shared variables
volatile int Kp = 1;                          // Proportional constant   

void feedback360();                           // Position monitoring
void control360();                            // Position control

int main()                                    // Main function
{
  cog_run(feedback360, 128);                  // Run feedback360 in a cog
  cog_run(control360, 128);                   // Run control360 in a cog
  pause(100);                                 // Wait 1/10 s, might not need

  while(1)                                    // Main loop
  {
    print("Enter angle: ");                   // Prompt user for angle
    scan("%d", &targetAngle);                 // Get entered angle
    print("\r");                              // Next line
    while(abs(targetAngle - angle) > 4)       // Display until close to finish
    {
      print("targetAngle = %d, angle = %d\r", // Display target & measured
             targetAngle, angle);             
      pause(50);                              // ...every 50 ms
    }      
  }    
}


void feedback360()                            // Cog keeps angle variable updated
{
  int unitsFC = 360;                          // Units in a full circle
  int dutyScale = 1000;                       // Scale duty cycle to 1/1000ths
  int dcMin = 29;                             // Minimum duty cycle
  int dcMax = 971;                            // Maximum duty cycle
  int q2min = unitsFC/4;                      // For checking if in 1st quadrant
  int q3max = q2min * 3;                      // For checking if in 4th quadrant
  int turns = 0;                              // For tracking turns
  // dc is duty cycle, theta is 0 to 359 angle, thetaP is theta from previous
  // loop repetition, tHigh and tLow are the high and low signal times for 
  // duty cycle calculations.
  int dc, theta, thetaP, tHigh, tLow;         

  // Measure feedback signal high/low times.
  tLow = pulse_in(pinFeedback, 0);            // Measure low time 
  tHigh = pulse_in(pinFeedback, 1);           // Measure high time

  // Calcualte initial duty cycle and angle.
  dc = (dutyScale * tHigh) / (tHigh + tLow);
  theta = (unitsFC - 1) - ((dc - dcMin) * unitsFC) / (dcMax - dcMin + 1);
  thetaP = theta;

  while(1)                                    // Main loop for this cog
  {
    // Measure high and low times, making sure to only take valid cycle
    // times (a high and a low on opposite sides of the 0/359 boundary
    // will not be valid.
    int tCycle = 0;                           // Clear cycle time
    while(1)                                  // Keep checking
    {
      tHigh = pulse_in(pinFeedback, 1);       // Measure time high
      tLow = pulse_in(pinFeedback, 0);        // Measure time low
      tCycle = tHigh + tLow;
      if((tCycle > 1000) && (tCycle < 1200))  // If cycle time valid 
        break;                                // break from loop
    }      
    dc = (dutyScale * tHigh) / tCycle;        // Calculate duty cycle
    
    // This gives a theta increasing int the
    // counterclockwise direction.
    theta = (unitsFC - 1) -                   // Calculate angle
            ((dc - dcMin) * unitsFC) 
            / (dcMax - dcMin + 1);

    if(theta < 0)                             // Keep theta valid
      theta = 0; 
    else if(theta > (unitsFC - 1)) 
      theta = unitsFC - 1;

    // If transition from quadrant 4 to  
    // quadrant 1, increase turns count. 
    if((theta < q2min) && (thetaP > q3max))
      turns++;
    // If transition from quadrant 1 to  
    // quadrant 4, decrease turns count. 
    else if((thetaP < q2min) && (theta > q3max))
      turns --;

    // Construct the angle measurement from the turns count and
    // current theta value.
    if(turns >= 0)
      angle = (turns * unitsFC) + theta;
    else if(turns <  0)
      angle = ((turns + 1) * unitsFC) - (unitsFC - theta);

    thetaP = theta;                           // Theta previous for next rep
  }
}    


// Most rudimentary control system example, 
// just proportional.  This could be done
// in the same cog as the angle mesurement.                                            
void control360()                             // Cog for control system
{
  servo_speed(pinControl, 0);                 // Start servo control cog
  
  int errorAngle, output, offset;             // Control system variables
  
  while(1)                                    // Main loop for this cog
  {
    errorAngle = targetAngle - angle;         // Calculate error
    output = errorAngle * Kp;                 // Calculate proportional 
    if(output > 200) output = 200;            // Clamp output
    if(output < -200) output = -200;
    if(errorAngle > 0)                        // Add offset
      offset = 30;
    else if(errorAngle < 0)
      offset = -30;
    else
      offset = 0;     
    servo_speed(pinControl, output + offset); // Set output
    pause(20);                                // Repeat after 20 ms
  }    
}

We are still trying to make something out of it, because there is no point in giving up.

Greetings,
Matmax