OpenMV Master and OpenView receiver | Arduino Master - openMV receiver

Hi,


Is it possible for an openMV (master) to communicate with an other OpenMV(slave) through I2C, UART or SPI ? And Can the master send data to the slave and the vice versa?

I also tried to send data from an arduino Master to the I2C slave using the code below in the openMV. The transaction send() seems to work


OpenMV code

# I2C with the Arduino as the master device and the OpenMV Cam as the slave.
#
# Please wire up your OpenMV Cam to your Arduino like this:
#
# OpenMV Cam Master I2C Data  (P5) - Arduino Uno Data  (A4)
# OpenMV Cam Master I2C Clock (P4) - Arduino Uno Clock (A5)
# OpenMV Cam Ground                - Arduino Ground

import pyb, ustruct

text = "Hello World!\n"
data = ustruct.pack("<%ds" % len(text), text)
# Use "ustruct" to build data packets to send.
# "<" puts the data in the struct in little endian order.
# "%ds" puts a string in the data stream. E.g. "13s" for "Hello World!\n" (13 chars).
# See https://docs.python.org/3/library/struct.html

# READ ME!!!
#
# Please understand that when your OpenMV Cam is not the I2C master it may miss responding to
# sending data as a I2C slave no matter if you call "i2c.send()" in an interupt callback or in the
# main loop below. When this happens the Arduino will get a NAK and have to try reading from the
# OpenMV Cam again. Note that both the Arduino and OpenMV Cam I2C drivers are not good at getting
# unstuck after encountering any I2C errors. On the OpenMV Cam and Arduino you can recover by
# de-initing and then re-initing the I2C peripherals.

# The hardware I2C bus for your OpenMV Cam is always I2C bus 2.
bus = pyb.I2C(2, pyb.I2C.SLAVE, addr=0x12)
bus.deinit() # Fully reset I2C device...
bus = pyb.I2C(2, pyb.I2C.SLAVE, addr=0x12)
print("Waiting for Arduino...")

# Note that for sync up to work correctly the OpenMV Cam must be running this script before the
# Arduino starts to poll the OpenMV Cam for data. Otherwise the I2C byte framing gets messed up,
# and etc. So, keep the Arduino in reset until the OpenMV Cam is "Waiting for Arduino...".

buff =  bytearray(4)
while(True):
    try:
        bus.send(ustruct.pack("<h", len(data)), timeout=10000) # Send the len first (16-bits).
        try:
            bus.send(data, timeout=10000) # Send the data second.
            print("Sent Data!") # Only reached on no error.
        except OSError as err:
            pass # Don't care about errors - so pass.
            # Note that there are 3 possible errors. A timeout error, a general purpose error, or
            # a busy error. The error codes are 116, 5, 16 respectively for "err.arg[0]".

        try:

           bus.recv(buff,timeout = 10000)
           print("Data received!")
           print(">",buff)

        except OSError as err:
            pass
    except OSError as err:
        pass # Don't care about errors - so pass.
        # Note that there are 3 possible errors. A timeout error, a general purpose error, or
        # a busy error. The error codes are 116, 5, 16 respectively for "err.arg[0]".

Arduino Code

#include <Wire.h>
#define BAUD_RATE 19200
#define CHAR_BUF 128

void setup() {
  Serial.begin(BAUD_RATE);
  Wire.begin();
  delay(1000); // Give the OpenMV Cam time to bootup.
}

 void loop() {
   int32_t temp = 0;
   char buff[CHAR_BUF] = {0};

   Wire.requestFrom(0x12, 2);
   if(Wire.available() == 2) { // got length?

     temp = Wire.read() | (Wire.read() << 8);
     delay(1); // Give some setup time...

     Wire.requestFrom(0x12, temp);
     if(Wire.available() == temp) { // got full message?

       temp = 0;
       while(Wire.available()) buff[temp++] = Wire.read();

      } else {
      while(Wire.available()) Wire.read(); // Toss garbage bytes.
      }
   } else {
     while(Wire.available()) Wire.read(); // Toss garbage bytes.
   }

   Serial.print(buff);
   delay(2000); // Don't loop to quickly.

    if(Wire.available() == 2) 
    {
         Serial.print("\nIn");
         Wire.beginTransmission(0x12); // transmit to device #9
         Wire.write("Hey"); // sends x
         Wire.endTransmission(); // stop transmitting
         delay(1);
    }

 }



But when it comes to receive data from the arduino, it is not working. Am I missing anything?

Hi, please use the UART to send data. That has a fifo buffer to receive bytes. It makes a huge difference.

SPI and I2C are master/slave protocols which are designed to talk to simple chips which spend their whole life waiting to be accessed. The OpenMV Cam is usually processing an image meaning that when SPI/I2C traffic happens it’s not ready to receive it. It’s quite easy for the camera to generate SPI/I2C data but receiving it unless it’s waiting for it is hard.

If you see the OpenMV Cam Examples → Pixy Emulation → SPI/I2C examples you can see how this has to be done… it’s generally terrible. Basically, for I2C you have to sit and poll the I2C bus for data and do nothing but that. It kinda wastes all of the camera’s power. By using the UART the camera runs a lot faster.

Hi, I tested your code and it’s working fine (after some fixing). First issue you send data from OpenMV once and then wait to receive data from Arduino (but Arduino is waiting to receive data from OpenMV before sending), so you should remove the second “if (Wire.available() == 2)”. Also OpenMV expects to read 4 bytes (buff size) and Arduino sends only 3 bytes.

Here’s the fixed code, I also suggest you switch to UART it’s much easier to use:

# I2C with the Arduino as the master device and the OpenMV Cam as the slave.
#
# Please wire up your OpenMV Cam to your Arduino like this:
#
# OpenMV Cam Master I2C Data  (P5) - Arduino Uno Data  (A4)
# OpenMV Cam Master I2C Clock (P4) - Arduino Uno Clock (A5)
# OpenMV Cam Ground                - Arduino Ground

import pyb, ustruct

text = "Hello World!\n"
data = ustruct.pack("<%ds" % len(text), text)
# Use "ustruct" to build data packets to send.
# "<" puts the data in the struct in little endian order.
# "%ds" puts a string in the data stream. E.g. "13s" for "Hello World!\n" (13 chars).
# See https://docs.python.org/3/library/struct.html

# READ ME!!!
#
# Please understand that when your OpenMV Cam is not the I2C master it may miss responding to
# sending data as a I2C slave no matter if you call "i2c.send()" in an interupt callback or in the
# main loop below. When this happens the Arduino will get a NAK and have to try reading from the
# OpenMV Cam again. Note that both the Arduino and OpenMV Cam I2C drivers are not good at getting
# unstuck after encountering any I2C errors. On the OpenMV Cam and Arduino you can recover by
# de-initing and then re-initing the I2C peripherals.

# The hardware I2C bus for your OpenMV Cam is always I2C bus 2.
bus = pyb.I2C(4, pyb.I2C.SLAVE, addr=0x12)
bus.deinit() # Fully reset I2C device...
bus = pyb.I2C(4, pyb.I2C.SLAVE, addr=0x12)
print("Waiting for Arduino...")

# Note that for sync up to work correctly the OpenMV Cam must be running this script before the
# Arduino starts to poll the OpenMV Cam for data. Otherwise the I2C byte framing gets messed up,
# and etc. So, keep the Arduino in reset until the OpenMV Cam is "Waiting for Arduino...".

buff =  bytearray(4)
while(True):
    try:
        bus.send(ustruct.pack("<h", len(data)), timeout=10000) # Send the len first (16-bits).
        try:
            bus.send(data, timeout=10000) # Send the data second.
            print("Sent Data!") # Only reached on no error.
        except OSError as err:
            pass # Don't care about errors - so pass.
            # Note that there are 3 possible errors. A timeout error, a general purpose error, or
            # a busy error. The error codes are 116, 5, 16 respectively for "err.arg[0]".

        try:

           bus.recv(buff,timeout = 10000)
           print("Data received!")
           print(">",buff)

        except OSError as err:
            pass
    except OSError as err:
        pass # Don't care about errors - so pass.
        # Note that there are 3 possible errors. A timeout error, a general purpose error, or
        # a busy error. The error codes are 116, 5, 16 respectively for "err.arg[0]".



#include <Wire.h>
#define BAUD_RATE 19200
#define CHAR_BUF 128

void setup() {
  Serial.begin(BAUD_RATE);
  Wire.begin();
  delay(1000); // Give the OpenMV Cam time to bootup.
}

void loop() {
  int32_t temp = 0;
  char buff[CHAR_BUF] = {0};

  Wire.requestFrom(0x12, 2);
  if (Wire.available() == 2) { // got length?

    temp = Wire.read() | (Wire.read() << 8);
    delay(1); // Give some setup time...

    Wire.requestFrom(0x12, temp);
    if (Wire.available() == temp) { // got full message?

      temp = 0;
      while (Wire.available()) buff[temp++] = Wire.read();

    } else {
      while (Wire.available()) Wire.read(); // Toss garbage bytes.
    }
  } else {
    while (Wire.available()) Wire.read(); // Toss garbage bytes.
  }

  Serial.println(buff);
  delay(2000); // Don't loop to quickly.
  Serial.println("Sending");
  Wire.beginTransmission(0x12); // transmit to device #9
  Wire.write("1234"); // sends x
  Wire.endTransmission(); // stop transmitting
  delay(1);

}