Help with coding for a PAC6985 servo interface. Super green, here.

General project help for Adafruit customers

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
CosplayEngineer
 
Posts: 17
Joined: Fri Nov 11, 2022 12:44 pm

Help with coding for a PAC6985 servo interface. Super green, here.

Post by CosplayEngineer »

Hi all,
I've posted this in another sub forum, but I am hoping maybe THIS is the place for code specific help? If not, mods please put this where it needs to go.

So, I am pretty new and novice with arduino stuff. The most I have done is copy and modify code for LEDs, and a Halloween skull that follows people using phototransitors.

I am currently looking at a cosplay project that requires 8 servos (MG995), with 4 pairs all moving different directions and different angles.

So far I am seeing that the PAC6985 interface should help with the number of servos, but I am a little over my head with programming these.

Here is what the servos will need to do when a momentary button is pressed:

"Top left" - rotate CCW 34°
"Top right" - rotate CW 34°
"Bottom left" - rotate CCW 31°
"Bottom right" - rotate CW 31°

When button is not pressed, I think I can just have them all at 90.

They also need to initiate at the "not pressed" states, as the servos are mounted on their sides, and do have a restricted range of motion, with the arm/horn attached.

I hope that all made sense.

The code below is what I have attempted, but it won't compile because of "expected primary-expression before ) token", at the line "for(int angle =90; )"??

I am not sure what I am doing wrong or how to fix this. I attempted to grab and modify code from Robojax tutorials.

Would anyone be able to assist with the code for this? I am realllly lost with this interface. I could do this through a regular arduino, if I was using less servos, but this interface thing has be baffled.

Code: Select all

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>

// called this way, it uses the default address 0x40
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
// you can also call it with a different address you want
//Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x41);

// Depending on your servo make, the pulse width min and max may vary, you 
// want these to be as small/large as possible without hitting the hard stop
// for max range. You'll have to tweak them as necessary to match the servos you
// have!
// Watch video V1 to understand the two lines below: http://youtu.be/y8X9X10Tn1k
#define SERVOMIN  125 // this is the 'minimum' pulse length count (out of 4096)
#define SERVOMAX  575 // this is the 'maximum' pulse length count (out of 4096)

// our servo # counter
uint8_t servonum = 0;

void setup() {
  Serial.begin(9600);
  Serial.println("16 channel Servo test!");

  pwm.begin();
  
  pwm.setPWMFreq(60);  // Analog servos run at ~60 Hz updates

  //yield();
}

// the code inside loop() has been updated by Robojax
void loop() {

    //watch video for details: https://youtu.be/bal2STaoQ1M
    for(int angle =90; )
    delay(50);

    {
  if(digitalRead(2)==LOW){
    pwm.setPWM(0, 0, angleToPulse(56) );
    pwm.setPWM(4, 90, angleToPulse(56) );
    delay(10)
    pwm.setPWM(1, 0, angleToPulse(124) );
    pwm.setPWM(5, 0, angleToPulse(124) );
    delay(10)
    pwm.setPWM(2, 0, angleToPulse(59) );
    pwm.setPWM(6, 0, angleToPulse(59) );
    delay(10)
    pwm.setPWM(3, 0, angleToPulse(121) );
    pwm.setPWM(7, 0, angleToPulse(121) );
    delay(10);
  }
    else
    
    pwm.setPWM(0, 0, angleToPulse(90) );
    pwm.setPWM(4, 0, angleToPulse(90) );
    delay(10)
    pwm.setPWM(1, 0, angleToPulse(90) );
    pwm.setPWM(5, 0, angleToPulse(90) );
    delay(10)
    pwm.setPWM(2, 0, angleToPulse(90) );
    pwm.setPWM(6, 0, angleToPulse(90) );
    delay(10)
    pwm.setPWM(3, 0, angleToPulse(90) );
    pwm.setPWM(7, 0, angleToPulse(90) );
    delay(10);

  
}

  
// robojax PCA9865 16 channel Servo control
  delay(1000);
 
}

/*
 * angleToPulse(int ang)
 * gets angle in degree and returns the pulse width
 * also prints the value on seial monitor
 * written by Ahmad Shamshiri for Robojax, Robojax.com
 */
int angleToPulse(int ang){
   int pulse = map(ang,0, 180, SERVOMIN,SERVOMAX);// map angle of 0 to 180 to Servo min and Servo max 
   Serial.print("Angle: ");Serial.print(ang);
   Serial.print(" pulse: ");Serial.println(pulse);
   return pulse;
}

User avatar
Franklin97355
 
Posts: 23910
Joined: Mon Apr 21, 2008 2:33 pm

Re: Help with coding for a PAC6985 servo interface. Super green, here.

Post by Franklin97355 »

It probably belongs in General help. I moved it for you.

User avatar
CosplayEngineer
 
Posts: 17
Joined: Fri Nov 11, 2022 12:44 pm

Re: Help with coding for a PAC6985 servo interface. Super green, here.

Post by CosplayEngineer »

Franklin97355 wrote: Sat Nov 12, 2022 1:16 pm It probably belongs in General help. I moved it for you.
Well dang. As you already know, my original thread was posted to General. Can you please delete this thread, then? No point in having two of the same thread. Sorry.

User avatar
adafruit_support_mike
 
Posts: 67446
Joined: Thu Feb 11, 2010 2:51 pm

Re: Help with coding for a PAC6985 servo interface. Super green, here.

Post by adafruit_support_mike »

Your whole loop() function is incorrect code.

It should be arranged like this:

Code: Select all

void loop () {
    for ( start_condition ; test ; increment ) {
        if ( condition ) {
            code_for_condition_true
        } else {
            code_for_condition_false
        }
    }
}
The for() loop above only has one item though:

Code: Select all

    for(int angle =90; )
Then it has another statement, and an opening brace:

Code: Select all

    for(int angle =90; )
    delay(50);

    {
Then there's a conditional whose 'else' clause isn't wrapped in braces:

Code: Select all

  if(digitalRead(2)==LOW){
    [ . . . ]
  }
    else
    
    [ . . . ]
And the extra open brace from above is never balanced by a close brace.

As it happens, the C/C++ compiler considers some of those things acceptable for hair-splitting reasons.

Strictly speaking, for() if() and 'else' need to be followed by 'expressions', which can be a single line of code:

Code: Select all

    for ( int i=0 ; i < 10 ; i++ ) 
        printf( "Hi!\n" );
will print "Hi!" ten times, and:

Code: Select all

    int x = 1;
    
    if ( 0 == x % 2 )
        printf( "x is even\n" );
    else
        printf( "x is odd\n" );
will print "x is odd".

Technically, braces are only necessary to turn a list of expressions into a single 'block' expression:

Code: Select all

    pwm.setPWM(0, 0, angleToPulse(56) );    // <-+
    pwm.setPWM(4, 90, angleToPulse(56) );   //   |  a
    delay(10)                               //   |
    pwm.setPWM(1, 0, angleToPulse(124) );   //   |  list
    pwm.setPWM(5, 0, angleToPulse(124) );   //   |
    delay(10)                               //   |  of
    pwm.setPWM(2, 0, angleToPulse(59) );    //   |
    pwm.setPWM(6, 0, angleToPulse(59) );    //   |  twelve
    delay(10)                               //   |
    pwm.setPWM(3, 0, angleToPulse(121) );   //   |  expressions
    pwm.setPWM(7, 0, angleToPulse(121) );   //   |
    delay(10);                              // <-+

- vs -

    {                                           //  one block (that contains twelve expressions)
        pwm.setPWM(0, 0, angleToPulse(56) );  
        pwm.setPWM(4, 90, angleToPulse(56) ); 
        delay(10)
        pwm.setPWM(1, 0, angleToPulse(124) );
        pwm.setPWM(5, 0, angleToPulse(124) );
        delay(10)
        pwm.setPWM(2, 0, angleToPulse(59) );
        pwm.setPWM(6, 0, angleToPulse(59) );
        delay(10)
        pwm.setPWM(3, 0, angleToPulse(121) );
        pwm.setPWM(7, 0, angleToPulse(121) );
        delay(10);
    }
You can even omit the start, test, and increment expressions in a for() loop:

Code: Select all

    for (;;) {    //  loop forever
    }
But you do have to give it the two semicolons so the compiler knows what you skipped.

Omitting braces falls under the heading of, "yes it's legal.. don't do it" because it will almost always bite you in the future. Eventually you'll want to add another line to a conditional or a loop, and the compiler will treat it as 'not the first expression after the for()/if()/else' and won't execute it the way you wanted.

Some people will claim it saves unnecessary keystrokes, but that excuse died about the same time as punch cards and teletypes. As of 2022 hard drive storage costs about $1 per 10 GB, putting one byte at about ten billionths of a cent.. vanishingly small compared to the depreciation of the keyboard switches while typing the characters. The slightest possible convenience for anyone reading or modifying the code later outweighs the cost of a couple more keystrokes.


Grammar problems like the ones in the code above are often a symptom of cutting and pasting.. another item on the programmer's "don't" list.

Yes retyping chunks of code can be tedious, but it takes far less time than trying to figure out how some cut-and-paste edit messed things up. The correct way to save typing is to wrap code in a function, not to let the computer haul text around in bulk. Having to type code manually also gives you time to think about what the code is doing, and forces you to use your judgement (which the computer can't duplicate) as you go.

Locked
Please be positive and constructive with your questions and comments.

Return to “General Project help”