I2C commander on Linorobot2

I’ve been playing with Linorobot2 a bit and have it compiling for ESP32 with SimpleFOC & SimpleFOCdrivers from Platformio.

I’d like to add I2C commander interface to it but have no clue what I’m doing: linorobot2_hardware/default_motor.h at galactic · rosmo-robot/linorobot2_hardware · GitHub

For @runger mainly I guess but I thought I’d ask here in case it’s useful for others. Is there any example code? Or could someone help me edit the above file?

Hey @Sam ,

I took a quick look, and am a bit confused as to what’s going on…

Are you trying to replace the motor driver, with I2CCommander being used to receive commands, or the central MCU, with I2CCommander sending commands?

Or both, I guess?

To add a basic instance of I2CCommander, once the library is included in the project, you can have code similar to this:

#include "SimpleFOCDrivers.h"
#include "comms/i2c/I2CCommander.h"

// commander instance
uint8_t i2c_addr = 0x60;  // can be anything you choose
I2CCommander commander;
// interrupt callbacks
void onReceive(int numBytes) { commander.onReceive(numBytes); }
void onRequest() { commander.onRequest(); }


// ... other variables, like sensor, etc...
BLDCMotor motor = BLDCMotor(POLE_PAIRS);


void setup() {
    
    // ...other setup code

    Wire.setClock(400000);          // use same speed on controller device
    Wire.begin(i2c_addr, true);     // initialize i2c in target mode
    commander.addMotor(&motor);     // add a motor
    //commander.addMotor(&motor2);  // you could add more than one motor
    commander.init(i2c_addr);       // initialize commander
    Wire.onReceive(onReceive);      // connect the interrupt handlers
    Wire.onRequest(onRequest);

}

It’s not so hard to use. The integration and initialisation of BLDCMotor and making it all run on SimpleFOC instead of whatever it was using before will be more work I think.

Note that each motor driver needs its own I2C address if they’re to be connected to the same bus…

I didn’t look much into Linobot, but I assume it is supposed to communicate with ROS via serial comm (I can see that the arduino code is reading topics directly).

Linobot MCU receives commands via serial from ROS and commands the motor drivers via pwm.

How exactly are you integrating simplefoc in linobot code?
From my understanding, you just integrated simplefoc in the linobot code to run it all on the same MCU, and I am sorry to say this, but you will most probably have very poor performance if that’s the case (serial comm will mess up your loop timings).

What are you trying to achieve with I2C?

For optimal performance, you would need to run SimpleFoc on a separate MCU. You could send I2C commands to simplefoc mcu via I2C instead of PWM.

In that scenario, you would need to rewrite the part of the code that is sending pwm to motor drivers to send I2C commands to simplefoc instead.

I would do it this way, but it depends on what are you building. A fast RC car commanded from ROS will probably suffer from low speed I2C, but for a slow moving platform, I2C will be enough. Just be careful to stop it if any of the communication protocols fails - or you will crash and destroy whatever you are making.

If you need more reliable and faster communication between main MCU and SimpleFOC, you probably should not go for I2C.

I’m connecting a ‘Brain’ ESP32 to Rosmo ESC the ESC is already running I2C commander. It’s the ‘brain’ code I want help with here.

Yes, this is what I’m trying to achieve.

Is this kinda right linorobot2_hardware/default_motor.h at master · samuk/linorobot2_hardware · GitHub

With linorobot2_hardware/motor.h at 5aec186abe70e0b79bc474a582b96e960ba6a319 · samuk/linorobot2_hardware · GitHub

Hi Sam!

Gotcha! The brain code is actually much simpler. What you’ve got at the moment is the receiving side, so that isn’t right. Sorry I sent the wrong example for your case.

On the sending side on the ESP32, you want something more like this:

#include <SimpleFOC.h>
#include "SimpleFOCDrivers.h"
#include "comms/i2c/I2CCommanderMaster.h"


// our RosmoESC's address...
#define TARGET_I2C_ADDRESS 0x60


// global instance of commander - controller device version
I2CCommanderMaster commander;

void setup() {
    // slow start - give RosmoESC a chance to boot up, serial to connect, etc...
    delay(1000);

    // this is a debug setup so initialize and wait for serial connection
    Serial.begin(115200);
    while (!Serial);

    while (!Wire.begin(21, 22, 100000)) {    // standard wire pins for ESP32 PICO Kit v4 
        Serial.println("I2C failed to initialize");
        delay(1000);
    } 
    commander.addI2CMotors(TARGET_I2C_ADDRESS, 1); // only one motor in my test setup
    commander.init();
    Serial.println("I2C Commander intialized.");
}

Then in your remaining code, you can make calls like:

uint8_t status[4];
int numRead = commander.readRegister(0, REG_STATUS, status, 4); // 0 is the motor number
if (commander.writeRegister(0, REG_TARGET, &targetSpeed, 4)!=4) { // 0 is the motor number
        // TODO handle I2C error
}

and things like that.

But you’ll have to consider the control architecture of the robot, its actually not simple. We can have a chat about it sometime.

For the moment you can just get rid of all the motor initialisation stuff, and replace the functions forward() and backward() with implementations that set the target speed via I2C…

1 Like

I’m currently playing with some code for ESP32 (I2C master) the existing code provides a hotspot & webui for controlling a car using a simple UART protocol

I have it compiling with SimpleFOC using Platformio. In the code I’ve commented out the //original UART code and noted where I need //I2C version:

Any help filling in those blanks would be great.

I sent a pull-request on GitHub - I cleaned it up a bit and fixed the I2CCommander related code, but not knowing the details of the web socket protocol it doesn’t make much sense to me as it is… direction_1 and direction_2 are sent in parallel? What’s the intent? As is, the code would always process direction_2 after direction_1, and whatever comes in direction_2 would effectively set the motors. So as is the options would be L, R and stop, and U and D would just be ignored…

1 Like

Nice, thanks! I’ll take a closer look. Did you push your commit already? Not seeing it here? Commits · runger1101001/ESP32-robot-car-controller · GitHub

Huh, you’re right the commit wasn’t a pull-request yet. It is now…

1 Like

The original code does this

https://photos.google.com/share/AF1QipNzkJ3I32igEO35I39o7b9hk5wTVOVDLoF2c14NpLEk1vOaEhjajYa6vF0aSnffyQ/photo/AF1QipPzka4THk1ykvPUU8-ep43W7fh3JNeHz3ntAFbg?key=aWtuSUlSd3dROW5QemlIdlJOTGxqcWFvakpucXhn

These are the differences between the original and our modified files