Problem using cloud functions with servos and motors


#1

In a project I am doing, I am using a HTML page with two range sliders that will control the direction and power of the servos and motors respectively. I have ran into a issue when both are hooked up and ran at the same time. When I input a 2 for setTurn, it will turn the servos but with 0 and 1 nothing will happen. When the power of the motors are increased to 25,50,75 or 100, the servo hooked up to A5 will turn position by about 5 degrees. I am not sure why this happening because when the motor code is excluded, the servos run how they were intended to. Below is the code for the program. I am also using a particle photon and a DRV8833 motor driver from Adafruit.

#define AIN_1 D2
#define AIN_2 D3
#define BIN_1 D1
#define BIN_2 D0
Servo myservoleft;
Servo myservoright;


void setup() {
  myservoleft.attach(A4);
  myservoright.attach(A5);
pinMode(AIN_1, OUTPUT); 
pinMode(AIN_2, OUTPUT); 
pinMode(BIN_2, OUTPUT);
pinMode(BIN_1, OUTPUT);
     myservoleft.write(80); //sets motor and fin to neutral state
     myservoright.write(80);
    delay(300);
    analogWrite(AIN_2, 0);
    analogWrite(AIN_1, 0);
    analogWrite(BIN_2, 0);
    analogWrite(BIN_1, 0);
  
  Serial.begin(9600);   

}

void loop() {
   Particle.function("direction", setTurn);
    Particle.function("power", setSpeed);

}



int setTurn(String turn){
 if(turn == "0"){
      myservoleft.write(170);
      myservoright.write(170);
     delay(300);
     return 0;
    }else if(turn == "1"){
        
    myservoleft.write(80);
    myservoright.write(80);
     delay(300);
     return 1;
    }else if(turn == "2"){
       
     myservoleft.write(5);
     myservoright.write(5);
     delay(300);
    return 2;
    
}
}

int setSpeed(String speed){
    if(speed == "100"){
     analogWrite(AIN_2, 0);
    analogWrite(AIN_1, 255);
    analogWrite(BIN_2, 0);
    analogWrite(BIN_1, 255);
    return 1;
    }else if(speed == "75"){
         analogWrite(AIN_2, 0);
    analogWrite(AIN_1, 191.25);
     analogWrite(BIN_2, 0);
    analogWrite(BIN_1, 191.25);
    return 1;
    }else if(speed == "50"){
        analogWrite(AIN_2, 0);
    analogWrite(AIN_1, 135);
    analogWrite(BIN_2, 0);
    analogWrite(BIN_1, 135);
    return 1;
    }else if(speed == "25"){
         analogWrite(AIN_2, 0);
    analogWrite(AIN_1,105);
    analogWrite(BIN_2, 0);
    analogWrite(BIN_1, 105);
return 1;

    }else if(speed == "0"){
         analogWrite(AIN_2, 0);
    analogWrite(AIN_1, 0);
     analogWrite(BIN_2, 0);
    analogWrite(BIN_1, 0);
  return 1;
    }
}

#2

@Cpargy, your Particle.function() declaration need to go in at the start of setup() and not in 'loop()`. Fix that and then test again.


#3

Just tried that but unfortunately did not solve the problem. I did have it there when the problem originally started happening but moved it to loop to see if it solved anything but obviously it did not.

Some additional information about what occurs when the program runs is that when the program is flashed the neutral state commands work in setup() but on the HTML page the 1 and 2 input do not cause the servos to turn but the 0 does. If the 100 input is set on the motors then the A5 servo moves forward 5 degrees from the setTurn() 0 state. Same thing happens if setSpeed() is 75,50 or 25. If the power is reduced to 25 then back up to 50 but not 75,100 the servo will move back about 5 degrees from its current position.


#4

As @peekay123 has suggested you MUST have Particle.function() called from early in setup() and not in the loop() being repeatedly redeclared. The real problem IMHO is with the structure of your calling of the myservoleft and myservoright from within the function handlers setTurn and setSpeed. A much better approach is to implement the function handler to set a global variable and then have logic in the loop() act on the values set or even test for a change and only issue updates to the motor driver and servos when a change is demanded. The other key reason for doing it this way is that moving the servo takes time and sticking in a fixed delay will not work. Also, to stop servo buzz or judder you need to detach the servos. I have included some code below from a halloween skull that might help you.

By the way analogWrite(pin, value); the value is of type uint8_t and not a float (191.25)!

void loop()
{
    neckControl();
}
// updates the current angle in <neckAngle> after implementing move
// target angle is set in <toNeckAngle> and speed in <neckSpeed> which is the step
void neckControl()
{
    int nextAngle;
    nextAngle = neckAngle;
    if (toNeckAngle > neckAngle) //positive rotation
    {
        nextAngle += neckSpeed;
        if (nextAngle > toNeckAngle) nextAngle = toNeckAngle;   //reduce step to target
    }
    else if (toNeckAngle < neckAngle)
    {
        nextAngle -= neckSpeed; 
        if (nextAngle < toNeckAngle) nextAngle = toNeckAngle;   //reduce step to target
    }
    if (toNeckAngle != neckAngle)               //not yet arrived at destination
    {
        myservo1.attach(neckServoPin);          // attaches the servo1 on the D0 pin to the servo object
        myservo1.write(nextAngle);              // tell servo to go to position in variable 'nextAngle'
        delay(neckSpeed*5);                     // waits 5ms per degree for the servo to reach the position
        neckAngle = nextAngle;
        myservo1.detach();  // detaches the servo1 on the D0 pin to the servo object to stop judder
    }
}
//
int neckCommand(String data)
{
    if (data == "left")
    {
        toNeckAngle = 0;
        neckSpeed = 60;
        return 1;
    }
    else if (data == "right")
    {
        toNeckAngle = 120;
        neckSpeed = 60;
        return 2;
    }
    else if (data == "centre")
    {
        toNeckAngle = 60;
        neckSpeed = 60;
        return 3;
    }
    else if (data.startsWith("angle"))
    {
        String pvalue = data.substring(5);
        int i = pvalue.toInt();
        if (i < 0 || i > 120) return -4;        // request OK but value out of valid range 
        toNeckAngle = i;
        toNeckAngle > neckAngle ? neckSpeed = toNeckAngle-neckAngle : neckSpeed = neckAngle - toNeckAngle;
        return 4;                               // request and value OK
    }
    else
    {
        return -99;
    }
}

#5

Thank you using servo.detach() solved all my issues.