How to connect one or more VIQ brains to each other

Back in the day of the PIC you could take two PIC brains and make them talk back and forth across the serial ports.

In a more recent day you could take the Cortex brains and use the serial ports to talk back and forth.

I thought there was a way described by @jpearman to do this with VEXIQ brains but I’m coming up empty.

The Goal is to set up B1 to be the joystick brain. It would read sensor values off of the second brain B2 and send it motor controls. I think I’m being stopped by the way the I2C connections are set up. But thinking the group as a path forward.

Not sure if this is too relevant, but once I connected 2 IQ brains and when I turned one(connected by a normal wire for motors) it would turn on the other, and when I turned one off, it would turn off the other.

Yep, you were correct, that wasn’t helpful.

3 Likes

You would need to build a special cable (ie. modify an IQ cable) and you could then use serial communication between two brains. Ports 1, 6, 7 and 12 on a gen 2 brain have this capability, but it’s not really documented. The easiest API is probably to use standard C fileio, open a port as “/dev/port1” etc. and then use read and write.

7 Likes

In terms of the cable.
I would disconnect wires going to pins 1, 2 and 5.
Then pins 3 and 6 need to be swapped (ie it becomes a crossover cable).
When configured as serial, I2C clock becomes TxD and I2C data becomes RxD.

I’ve not tried this between two IQ brains, only from a brain to other device such as an Arduino, but it should work.

6 Likes

OK, I have some downtime (oh sorry, time not allocated to other more important projects) that I can give it a shot. Any tips on the software side or just bitbang the I2C stream?

I’m suggesting the ports are configured to use asynchronous serial at 115200 baud or whatever you choose, not i2c. I’ll try and put something together at the weekend as a demo. ports 1, 6, 7 and 12 are special because they have their own dedicated connection to the cpu, the bus is not shared with other ports. We can configure them to use generic i2c (only as master, not slave), async serial or as gpio (2 out, 1 input IIRC).

and I should clarify, this is only with generation 2 brains.

5 Likes

Ok, good to know, I’ll hang out and wait some. But the concept of

  • Controllers into Radio 1 / Brain 1
  • Control out to Ports 1, 6, 7, 12 to Ports 1 on external brains gives me a 1 master 4 brain listener pod with lots of duplicate code (we all listen to 1) an then have 11 ports for sensors, motors, etc.

Well past what I was looking to be able to do.

Thanks!

Here’s a very simple demo using two IQ2 brains. crossover cable (swap scl/sda) with gnd is needed, disconnect power and the other signals.

One sends (well, technically they both send in this demo) the string “Hello” the other is receiving it.

Here is the C++ code, in practice for reliable communication you need to invent a suitable protocol handling partial reception of data, error checking etc.

C++ demo code
/*----------------------------------------------------------------------------*/
/*                                                                            */
/*    Module:       main.cpp                                                  */
/*    Author:       james                                                     */
/*    Created:      12/9/2022, 2:42:19 PM                                     */
/*    Description:  IQ2 project                                               */
/*                                                                            */
/*----------------------------------------------------------------------------*/
#include <fcntl.h>
#include <unistd.h>
#include "vex.h"

using namespace vex;

// A global instance of vex::brain used for printing to the IQ2 brain screen
vex::brain       Brain;


void
transmitTask() {
    int fd = 0;
    int nTotalTx = 0;

    fd = open("/dev/port1", O_RDWR );

    if( fd < 0 ) {
      printf("port error\n");
      return;
    }

    while(true) {
      int nWritten = write( fd, "Hello", 5);

      nTotalTx += nWritten;
      Brain.Screen.printAt( 5, 30, "tx: %8d", nTotalTx);

      this_thread::sleep_for(50);
    }
}

void
receiveTask() {
    int fd = 0;
    static char buf[128];
    int nTotalRx = 0;

    fd = open("/dev/port7", O_RDWR );

    if( fd < 0 ) {
      printf("port error\n");
      return;
    }

    // set input non-blocking
    fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);

    while(true) {
      // non blocking read
      int nRead = read( fd, buf, sizeof(buf) );

      // see if we have any characters
      if( nRead > 0 ) {
        // print to stdout in hex
        for(int i=0;i<nRead;i++) {
          printf("%02X ", buf[i]);
        }        
        printf("\n" );

        nTotalRx += nRead;
        Brain.Screen.printAt( 5, 50, "rx: %8d", nTotalRx);
      }

      this_thread::sleep_for(10);
    }
}

int main() {
    thread ttx(transmitTask);
    thread trx(receiveTask);

    printf("started\n");

    while(1) {
        // Allow other tasks to run
        this_thread::sleep_for(10);
    }
}

Python code would be very similar.

13 Likes

Here’s the Python version

Python demo code
# ---------------------------------------------------------------------------- #
#                                                                              #
# 	Module:       main.py                                                      #
# 	Author:       james                                                        #
# 	Created:      12/9/2022, 3:56:29 PM                                        #
# 	Description:  IQ2 project                                                  #
#                                                                              #
# ---------------------------------------------------------------------------- #

# Library imports
from vex import *

# Brain should be defined by default
brain=Brain()

def transmit_task():
    totalTx = 0
    nWritten = 0
    try:
        fd = open("/dev/port1", "wb")
    
        while(True):
            nWritten = fd.write(b"Hello")
            totalTx += nWritten
            brain.screen.print_at( "tx: %8d" % totalTx, x=5, y=30)
            sleep(50)
    except:
        print("port error")
        return

def receive_task():
    totalRx = 0
    bytes = 0
    nRead = 0
    try:
        fd = open("/dev/port7", "rb")
    
        while(True):
            bytes = fd.read()
            nRead = len(bytes)
            if nRead > 0:
                for b in bytes:
                    print("%02X" % b, end=" ")
                print("")
                totalRx += len(bytes)
                brain.screen.print_at( "rx: %8d" % totalRx, x=5, y=50)
            sleep(10)
    except:
        print("port error")
        return

ttx = Thread(transmit_task)
trx = Thread(receive_task)
print("started")
8 Likes

My apologies, I am unaware of the technical side of VexIQ Brains, if you were to go about this, could you upload it through VexcodeIQ? Or would you have to upload it through VS?