Go Down

Topic: Servo i2c using an external master (Read 74 times) previous topic - next topic

ggxyz

Hi, Im trying to extrenally control a servo using arduino over i2c. this i2c master will send a byte("3" in this case) to trigger the servo to go to a position and come back to start position.
The servo does not get triggered this way. I am able to make it work with 2 commands( "3" to deploy and "4" to retract) but i want to send only a single command to do the complete loop. Any help would be appreciated


I think the problem might be with the arduino getting confused about the pos value after the first for loop. Any way to control this? i tried using separate variables for deploy and retract but that did not help



//slave receiver
#include<Wire.h>
#include<Servo.h>


Servo myservo;
int pos;


void setup() {
 // put your setup code here, to run once:
 Wire.begin(8 );                 // serial comm at address 8
 Wire.onReceive(receiveEvent);  // create event for serial comm
 Serial.begin(9600);            //baud rate
  myservo.writeMicroseconds(1500);
  myservo.attach(8,900,2100);             //servo on pwm pin 9 (c8 of teensy)
;
 pinMode(LED_BUILTIN, OUTPUT);  // led indicator

}
void loop() {
 
}

void receiveEvent(int howMany) {    //activates when a byte is recieved

     while (0 < Wire.available()) { // event starts when serial comm is available and master sends a byte   
       byte c = Wire.read();         // read byte
          if(c==51){   //3=51,4=52
                    deploy();
                    delay(500);
                    retract();
            }
          }     
        }

void deploy()
{
    digitalWrite(LED_BUILTIN, HIGH);  // led on when byte is available
    for (pos=1500; pos<=2100;pos+=100) { // travel 60 degrees
            myservo.writeMicroseconds(pos);              // tell servo to go to position in variable 'pos'
            delay(50);                       // waits 20ms for the servo to reach the position
          }
}     

void retract()
{
digitalWrite(LED_BUILTIN, LOW);
  for (pos=2100; pos>=1500; pos-=100) { // travel 60 degrees
            myservo.writeMicroseconds(pos);              // tell servo to go to position in variable 'pos'
             delay(50);                       // waits 20ms for the servo to reach the position
          }     
}


pylon

Always the same error:

Code: [Select]
void receiveEvent(int howMany) {    //activates when a byte is recieved

     while (0 < Wire.available()) { // event starts when serial comm is available and master sends a byte   
       byte c = Wire.read();         // read byte
          if(c==51){   //3=51,4=52
                    deploy();
                    delay(500);
                    retract();
            }
          }     
        }


receiveEvent is called in interrupt context and must not call any function that depends on interrupts. delay()  (to give you just an example) depends on interrupts and will block forever if called inside this handler.

ggxyz

you are right. i realised that too after some time. is there any way to achieve what i am trying to do without delay? i can always send 2 commands but i want to do just one.

GolamMostafa

Code: [Select]
void receiveEvent(int howMany)
{    //activates when a byte is recieved

     c = Wire.read();         // read byte  ; declare in global area : volatile byte c; volatile flag1 = false;
     flag1 = true;              //indication that receiveEvent() handler has been visited
}

void loop
{
   if(flag1 == true)
   {
       if(c==51)
       {   //3=51,4=52
          deploy();
          delay(500);
          retract();
          flag1 = false;
        }       
    }
}

Go Up