Issue controlling Servos after receiving 4 integers via I2C

Medication Dispensing Machine - School Project

Intended Use:

MySQL database containing a Table of patients and their prescribed medications is already created. It consists of 3 patients and 3 possible medications available to each person. Simplified for proof of concept.

Upon execution of pytohn code, RPI will ask the user which patient info to access (int value of 1-4, 4 meaning all patients), followed by which medication to dispense for the patient(s). (this is also int value 1-4, 4 meaning all medications).

RPi now retrieves the correct info from the MySQL database and sends 4 ints to arduino VIA I2C, which then ‘decodes’ the 4 ints to decide which servo motor(s) to actuate, and for how many dispenses (per motor).

The RPI side is working as intended, and is properly sending out the correct 4 integers retrieved from database, and the arduino is properly receiving and saving the values in an array.

My issue is on the Arduino side. I am saving the received info in an array named ‘int data[4];’ At this point I want to rotate the corresponding servo motor a rotation (back and forth once) for as many times as needs dispensing.

Ex: for(i = 0; i < data[1]; i++)
where data[1] is number of rotations desired.

However when I run this, the servos barely respond.

Any help is appreciated! Also, I’m focusing in RF engineering, so plz dont judge my code too harshly as it is not a big interest for me.

Thanks =D

Master: RPi B+

—[Python Code Attached]—

Slave: Arduino Uno

#include <Wire.h>
#include <Servo.h>

#define SLAVE_ADDRESS 0x12

Servo servo1;
Servo servo2;
Servo servo3;

int pos1 = 0;
int pos2 = 0;
int pos3 = 0; 

void setup() {
  Serial.begin(9600);
  servo1.attach(2);                     
  servo2.attach(3);                     
  servo3.attach(4);
  Wire.begin(SLAVE_ADDRESS);
}

void loop() { 
  Wire.onReceive(receiveData);
  Wire.onRequest(sendData);
  delay(1000);
}

void receiveData(int byteCount){
  
  int i = 0;
  int data[4];
  int index = 0;
  
  while(Wire.available()){
    data[index] = Wire.read();
    index++;
  }
  
  Serial.println("if this prints once, while loops condition is fine");
  Serial.println(data[0]);
  Serial.println(data[1]);
  Serial.println(data[2]);
  Serial.println(data[3]);
  
  for(i = 0; i < data[1]; i++){
    for(pos1 = 0; pos1 < 180; pos1++){
      servo1.write(pos1);
    }
    for(pos1 = 180; pos1 > 0; pos1--){
      servo1.write(pos1);
    }
  }
  
}

void sendData(){
  // will continue w/ this portion after servo motors are good 2 go
}

i2c_comm.txt (17.9 KB)

i2c_comm.txt Attached file is my RPi python code

and sends 4 ints

Why does it send 4 ints to describe 2 4-bit values? One byte would be sufficient.

The onReceive() and onRequest() functions register handlers. That should be done ONCE, not once per second.

It is pointless to have loop() stuff it’s head in the sand. You are not charged per iteration of loop(). Ditch the stupid delay().

    for(pos1 = 0; pos1 < 180; pos1++){
      servo1.write(pos1);
    }

The write() method is non-blocking. This whole loop will complete before the servo has physically started to move. So will the next one, that puts the servo back. The end result will appear to be that the servo hasn’t moved at all. You need to delay() a while to see the movement. But, do NOT add delay() to this code, which is an ISR, where interrupts (including those that the servo class generates to move the servo) are disabled, so delay() won’t work.

Thanks for the response PaulS.

I am not too knowledgeable on bit/byte wise programming, which is why I wanted to send ints (b/c im familiar with them). There are 4 ints b/c there are 4 cases. In two of the cases, 2 ints is sent, and in the other 2 cases, 4 ints are sent.

I appreciate the clarification on the write() function too.

I was able to solve my issue though. I was saving the received data in local variables within onReceive() handler. So I created global variables, had onReceive() handler function update the global vars, then in the void loop() section, I created conditional statements based on the global vars to induce motor movement. And everything worked once I made the changes.

And everything worked once I made the changes.

Excellent. Thanks for providing the feedback.