Go Down

Topic: Servo i2c using an external master (Read 218 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;
        }       
    }
}

ggxyz

Hey GolamMostafa, thanks for the code. I tried implementing that but i am not able to get to the void loop.

//slave reciever teensy
#include<Wire.h>
#include<Servo.h>


Servo myservo;
int pos;
volatile int flag1=false;
volatile byte c;

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 receiveEvent(int howMany)
{    //activates when a byte is recieved

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

void loop()
{
   if(flag1 == true)
   {
       if(c==51)
       {   //3=51,4=52
          cut();
          Serial.println("x");
          delay(500);
          retract();
          flag1 = false;
        }       
    }
}


void cut()
{
    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
          }     
}


when i mean not getting in the void loop, the arduino monitor does not print "x" on the serial monitor, meaning the code does not reach the loop. Please confirm volatile int flag1 is correctly defined variable.

cattledog

You have both a global and local variable c.
Code: [Select]
volatile byte c; //global
int  c = Wire.read(); //local to the ISR


Which one do you think is being compared to here?
Code: [Select]
if(c==51)


You need to brush up on the concept of "Scope"
https://www.arduino.cc/reference/en/language/variables/variable-scope--qualifiers/scope/


Go Up