CAN BUS interface - SimpleFOC standard identifiers?

Ok, I’ve created a new sheet for the reworked format.
image

I’ve simplified the Get/Set into the Data Type:
image
Ie: “get value” has no data type - the data type is in the returned packet.

Technically - having a data type is not required, because it should always be the one data type for a command. But I think having it would make the protocol a bit more robust, as the CAN frame does not rely on the implementation version on both ends being correct.

The command list is flattened, and there are also larger ranges for: Bus Node ID, Motor ID, and over 200 free commands for future expansion.

This format also has the bonus that the bit boundaries align to nibbles, so in hex format it is human readable:

And: The lower 2 bytes are a unique ID for the Motor (Bus and Motor combined). Apart from motor id “ALL” - which may be more than 1 motor.
Byte 3 is the command.
Byte 4 is the data type (ignoring the upper bits that are not part of the CAN frame)

Bus level commands are still mixed with motor level commands - but they are separated by range. Eg commands 0xF0 - 0xFF are bus level commands. So when byte 3 = 0xF, then it’s a Bus level (MCU) command.

STM32 is similar. Older models have CAN peripherals, newer ones have FDCAN. They need an external tranciever to take the digital RX/TX signals to the differential CAN lines.
I would aim for only this kind of support, and leave it to those who want to use them to implement the CAN controller SPI code.

On the one hand I think 6 motors is more than enough from an ESC board point of view - I don’t really know of any MCUs that can do more than 4 motors in 6-PWM. Also from the point of view of speed and reading all the sensors and currents it seems quite unrealistic.

But I was thinking more along the lines of things other than ESCs as well. Since CAN is a bus, there might be other sensors and “brain” components on there too. What if you do a topology where a robot controller is in charge of 20 motors - not directly driving them itself, but forwarding the CAN messages. Or a “snake” robot with lots of segments - they mightn’t all have their own CAN controller.

I wasn’t able to articulate it very well, but I was trying to argue for a more flexible approach in this regard.

I’m still thinking on that. Basically star topologies aren’t really supported due to the termination. You should really have a long terminated “bus line” with short unterminated “node lines” to each node. Diverging from this will affect the bus speed you can achieve. But in my kind of robot, the bus is so short anyway it probably won’t be an issue no matter how you wire it up.
Star topologies are supported with hubs, but that is something I would avoid. My robots don’t want a CAN-hub.
So I would include optional termination on each node, and probably provide 2 CAN “ports” to the same lines, so the bus is built up by connecting from node to node with cables that have plugs on both ends. The two end nodes get their termination option switched on and the bus is up and running!

You are absolutely correct! In this case I was thinking more about the protocol definition and not really about implementing the functionality :smiley: (someone else’s problem?)
I think its ok to define the protocol with a bit of ambition, as long as there is a simple way to implement it for simple cases - e.g. the parameterised version could be specified in the protocol, but the actual ESC could ignore the actual name parameter and work with only one settings.

And as for the implementation itself, for ESP32 it will be quite easy, I think. But as you point out, there is no clear definition of what needs to be saved. Some users may want to save a lot more than just the motor alignment, e.g. PIDs, or even user settings.
And on other MCUs there may not be a NVRAM or writeable flash, and you might have to use an EEPROM or similar external chip.

For all these reasons I would leave the settings saving as a kind of open thing, where SimpleFOC defines stub functions (or classes) that the user has to implement in the end. The examples could then contain sample code for some common cases (like ESP32 writing to flash) and example data formats to get users started.

I like it!

Yes but now it’s just “commands”, no tree with mixing at the same level. The difference is subtle, but I think this is much better. With the other system users would have wound up abusing motor5 and motor6 to define their own commands. Now this is built-in.

This makes me think of IP4 addressing - where you have 32 bit identifiers, which works for everyone in the same way, but gets interpreted differently (split into host and subnet portions) by the networked nodes depending on their netmask settings. And there can be a broadcast address per subnet. :slight_smile:
Its a system so good we just can’t seem to move to IP6 ever. In the year 2100 we will somehow be running 1 trillion internet nodes on 32bit addresses and everyone will still be using IP4 :laughing:
So I think your new suggestion is a really excellent addressing scheme! We could even introduce a “nodeidmask”, and mix it up as needed.

Ok, I’ve got it listening to a command, and replying with the response on the CAN bus now:


I have requested the motor M Voltage Limit,
It has replied with the motor voltage limit of 1.0

For me to be able to intercept the return value from Commander, I’ve had to mark these methods as virtual in Commander.h:

virtual void print(const float number);
virtual void print(const int number);
virtual void print(const char* message);
virtual void print(const __FlashStringHelper *message);
virtual void print(const char message);
virtual void println(const float number);
virtual void println(const int number);
virtual void println(const char* message);
virtual void println(const __FlashStringHelper *message);
virtual void println(const char message);

And then override them in an inherited class: (The overridden functions just save the value, so that CAN can transmit it later.)
CommanderCAN command = CommanderCAN(can.stream);


Now, the bad news. Commander has a few sections like this:

  switch(motor->controller){
    case MotionControlType::torque:
      println(F("torque"));
      break;
    case MotionControlType::velocity:
      println(F("vel"));
      break;

Where it starts of with the number that I want - but then just prints out text.
I don’t want to re-write the Commander class - as this would need to continually be kept up to date.

Any ideas on options?

Do you think we could have a new VerboseMode::Binary - where it would print the responses as numbers instead of text?

Just in case it could interest you (which I doubt), I currently work on a high-speed/generic datalogging interface for my new SimpleFOCScope project (Yes I do know about SimpleFOCStudio, which I value much but I have very different design goals)

What I do is simply send a text header followed by a line break
Serial.println("PhaseCurrent_s")
and then I send the struct as is
Serial.write(&phaseCurrent, sizeof(phaseCurrent));

client side (I parse the .h using a python library, but that is OT) I do

 h = serial.readline()
if h in headers:
    bytes = serial.read(headers[h].itemsize)
    phaseCurrent = decode(bytes, headers[h].definition)

so it all remain very generic, and fairly fast (I still have to find a nice way of improving the “header_size”/sizeof(header)" ratio).

(that said I plan to use the commander api to send commands, only intend my stuff for the MCU → client comm)

1 Like

Thanks, that’s good to know!

I am doing similar with writing the value, but with CAN we have a 29 bit header and 8 byte body, so we cannot really use character strings, or large structures (without spanning multiple frames, or limiting to CAN-FD).

I think our goals for the CAN interface would be:

  • Support multiple nodes on the one bus
  • Support for CAN FD speeds, but backwards compatible to CAN
  • Allow use of as many SimpleFOC features as possible
  • Minimal changes for different platforms

Nice to have:

  • SimpleFOC Studio connection
  • Negotiation for Bus ID (to avoid having unique code flashed to each controller)
  • Saving/Loading settings to the controller
  • Integration with ROS2 / Isaac - maybe with a bridge

Ultimately: allow the easy use of multiple SimpleFOC actuators connected by CAN bus in a robotics platform.

:partying_face:

I think the binary mode isn’t a bad idea, it would improve the performance of the SimpleFOCStudio monitoring as well if we had such a mode.

For now I would go with the virtual functions or whatever works, and once it is in a shape you consider final, then we can look at how best to combine the Commander concepts (if possible) in an efficient way.

I would combine a set of values into a “frame”, where a frame shares a common timestamp.
The system could then send a “header frame” which describes the following frames, and then just send frames of data, one after the other, without sending more headers.

Perhaps something like this:
On the receiving side, you check the type of frame:
if its headers, reconfigure the reader for the new fields
if its data, read it in

The frame could start with a 32 bit timestamp/type field: 1 bit “type” (header/data) + 31 bit timestamp
Then follow the data elements as described by the header.

This kind of setup will result in much less overhead, I think.

Alright, some more testing:

Now I can (somewhat) control SimpleFOC over CAN using ROS2.

ROS2 Publisher → ROS2 Subscriber (for a Twist topic) → CAN → SimpleFOC

The publisher is just sending a sine wave for the position:

It’s all very statically coded at the moment, and it’s just some testing…

3 Likes

I’ve swapped to a RPi now, it’s more compact, and has better support.
I made my first bus with 2 motors - both ends have the termination resistor set:

And I could get SimpleFOC Studio to send commands to both motors with very few changes to it’s code. I’ve inherited simpleFOCConnector.py and replaced the Serial stuff with a ROS2 client.


I’ve used the “Command:” field to set the Bus Node ID that the command is addressed to.

My setup is as follows:

2 Likes

Awsome :slight_smile: I plan in the future to add support to Simple FOC studio to be able to configure control of multiple SimpleFOC devices connected to a CAN bus. Some time ago I made a CanBus sniffer project and I would also like to add it as an additional utility. It curet uses a proprietary serial commands but i wold like to evolve ir to a standardized interface.

https://github.com/JorgeMaker/CanSnifferSuite

Have you published the code in a public repository on how to connect SimpleFOC with ROS2 using CAN Bus?

It’s still work in progress, but I have all the code available:

Controller:
Communicates on CAN with SimpleFOC CAN Library
Here is an example use of this library with SimpleFOC. (Ignore the StealthController class - as these are functions specific to my hardware setup)
(The library requires these lines to be marked as “virtual” functions)
Communication on the CAN bus is done with this format.

RPi:
ROS2 packages src
I just symlink these packages into my workspace.

PC:
Same ROS2 packages as above
Changes to SimpleFOC Studio
(Simple FOC Studio needs the ROS2 overlays to be sourced before running it)

2 Likes

This CAN adapter looks quite cool for those using Teensy: https://www.tindie.com/products/fusion/dual-can-bus-adapter-for-teensy-40-41/

Has anyone managed to get this library running on an STM32 such as an F405 or F103? @Jason_Kirsons I see there is a hardware-specific option for the ESP32. I’m new to CAN and have watched some videos regarding CAN on STM32 and HALs, would I create a new file for the STM32 with the same structure as the ESP32 Hardware file? Would anything else in the other library need changing? Thanks

Hi Matt,

Yes - You should just have to implement these functions:

void _initCAN(int tx, int rx);
void _transmitCAN(uint32_t identifier, uint8_t *data, uint8_t length);
bool _receiveCAN(uint32_t *identifier, uint8_t *data, uint8_t *length);
void _getUniqueID(uint8_t * id);

(The last one is not critical)

I believe ESP32 and STM32 both have the same byte order, so I think the rest would be ok.

Hi Jason,

Have you got any documentation on how to use the library? I have looked at the CanCommander spreadsheet and can’t quite work it out. How would I get a cyclic update of the motor position and velocity etc?

Thanks

i am currently developing a can capable foc board and can tell you can implementation is very hardware specific down to the exact transceiver chip and mcu combination as well as canbus node placement in a configuration. designing a generic can bus library is perhaps very challenging in such a small development community as here. my board is already at revision 4 and i barely made it communicate. at that point i am seriously considering adding an spi middle man to handle the heavy lifting and using an spi library to drive the can nodes. i am using stm32.
Edit: I am using my own code, not the foc can implementation, so YMMV.
Edit2: I will post the design and code once I get it to a stable point.

1 Like

That doesn’t sound promising, hopefully, in my situation, I may be ok since my custom hardware is based on the Odrive schematics and using the same transceiver, TCAN334DCNR. I will try to get it going with @Jason_Kirsons library and if I have any success I will report back and may be useful for your application?

Is that the IGBT board you have been working on? I have been following along on that project and looks great. How far away are you from a stable point?

Have you looked into EtherCAT? There is a project that’s being worked on that is CIA402 compliant and Arduino compatible, It’s designed to be used on Odrive, STMBL, VESC, etc It’s an interesting read and brings the control level to an Industrial grade. https://kubabuda.github.io/ecat_servo/001-intro https://hackaday.io/project/181058-ecatservo https://github.com/kubabuda/ecat_servo

The IGBT board for me was a proof of concept and it worked, I mean, I proved you can run SimpleFOC with 15 volts and spin slowly a small motor, as originally the IGBT chip was designed for 650 volts 50 Amp industrial 30kW motors (yeah, that’s a 40 horse power motor, enough to run a modern compact car, the original Beetle was 25HP…)

The CAN-able board I am designing is using TI’s DRV8332 with integrated current sensing and STM32F103 as a one-stop solution. Also I have another board with 50Amp mosfet drivers but that’s in a design stage.

I looked into EtherCAT however this is too new and there is no stable and cost effective combination of hardware plus code base to run development. Plus it didn’t fit my requirements. And the cables required are too thick. I had a hell of a time even finding proper cables, and at that point I gave up, even cabling was a challenge. Can’t be miniaturized. Just the ethernet jack itself is bigger than the whole CANBUS SPI module I developed. EtherCAT is good if you connect big boxes and modules. When your design involves modules where extra few millimeters are a deal breaker, it’s out.

Don’t give up on the CAN, ask @runger or @Owen_Williams, they appear to have made it work. Also, when I get my board running I will post the schematics and the code.

Have you got the designs and schematics of the IGBT boards? I have some old Industrial 220V servo motors that I wouldn’t mind mucking around with in the future. got a 750W and1.5KW and maybe have access to a 380V 15kw soon.

What sort of power can the DRV8332 handle with good cooling? I’m currently using some RC Plane motors that peak at about 20-25A is that too much?

I have just come across @Owen_Williams SimpleCAN and reading through it now to see how I can use it with @Jason_Kirsons library. Still, a lot to get my head around and not as simple as I imagined it would be unfortunately.