CanBus Raspberry pi arduino

Hi i’m working on a project that has a raspberry pi as the brain and an Arduino that act as a node. I was wondering if can-bus is the best way to communicate and if it is how do I go about programming it in?

That’s certainly a way to do it. Though you have a problem of neither RPi or Arduino having CAN Bus natively. So you’d need to setup your own CAN Controller and Transceiver at each end, such as the common Arduino CAN shields that use MCP2515 CAN Controller and MCP2551 or MCP2561 CAN Transceivers https://www.seeedstudio.com/CAN-BUS-Shield-V2.html
To my knowledge the MCP2515 Controller is supported in Linux and its a SPI interface, so its pretty likely there are libraries for for both Arduino and RPi.

Other options include Serial, SPI, and I2C. Though be careful if your Arduino runs at 5V as that can damage the Pi which runs at 3.3V. So you’d want some kind of Level Shifter like one of these:


One solution I’ve used in the past is one of these RPi Arduino Shields from DFRobot Arduino Shields for Raspberry Pi B+/2B/3B/3B+ - DFRobot and use Serial, however the Serial for the Pi and Arduino aren’t actually connected to each other… The Switch just changes which device is talking to the XBEE Socket, so I ended up removing the switch and soldering it myself…

2 Likes

The other thing that I also looked in to is rs-485. It is a close relative of can-bus. Do you think that would also work?

You’d definitely be able to get higher data rates than CAN, but I’m not as familiar with it or what controllers are available, or their compatibility, but generally you’d have to use some kind of controller on each end as there isn’t native support on either processor.

From some googling the MAX485 seems very popular.

2 Likes

Depends on the situation… for the reasons mentioned above, I’d to lean towards saying “No, not optimal”, but it depends.

Is it just one PI and one arduino that are communicating? If so, RS232 serial (over USB) might be your best bet - PI supports it natively and it’s the “default” communication channel for arduino.

One thing to consider for most of the CAN hardware that’s in the < $50 range - the TX/RX buffers are not very deep. This means your application has to be very fast in order to service the chip regularly, and not have messages get dropped… and even that’s quite hard sometimes. This will limit effective data rates to below their theoretical limits for CAN bus.

I2C and SPI are two others that are commonly used, and largely supported by both platforms. You have to be careful to shift logic voltage levels sometimes (watch for 3.3v vs. 5v hardware). But, these would be a bit more robust against disconnects and reconnects than USB-serial.

CAN would make sense if there’s other CAN hardware involved, or you wanted the robustness provided by the twisted-pair and signaling inherent to CAN’s spec. It’s also good when you’ve got lots of peer devices needed to communicate across the same set of wires at the same time, without a central unit coordinating them all simultaneously.

Ethernet & TCP/IP is one final option. It adds a lot of complexity, but also a lot of flexibility to interface with other networks. Only the Arduino would require additional hardware. But, unless connecting to something else with Ethernet on it is a goal, probably not worth pursuing.

One final consideration: If you’re only looking to communicate a few boolean states (light on, light off, timer expired, etc.), using the GPIO pins on both devicecs may be a possibility.

3 Likes

@gerthworm @gixxy

This is the basic idea. I want to be able to have the nodes talk to the Raspberry pi which we call the brain. The brain will then communicate back and forth with the nodes. I’ve looked in to spi that has to many pins for the way i’m planning on connecting to it. I2c, I have to make a address for each one but if I could make it that the brain gives them an address then i would use that, but i dont think you can do that.

Gotcha, I think.

Address negotiation definitely adds an extra layer of complexity. At least for what I’ve seen, address negotiation isn’t part of normal I2C operation.

FWIW CAN, by itself, does not do device addressing, which might suit your purposes well. But, it’s a double-edged sword - in order to understand which node is sending data, I think you’d have to use some other higher-level protocol (ex: J1939’s address claim) or make one yourself.

Actually, based on your network diagram…I have a fairly similar setup around my house for small temperature sensors running on arduino platforms. I used ESP8266-based Wemos D1 modules, which have built in wifi connections. I configured my router to assign static IP addresses to each to make organization easy, but they could just as easily DHCP and connect to the central “brain” raspberry pi to start delivering data. The raspberry pi would just have to listen for incoming connections. I’m transferring temp/humidity data about once a second over the network to a central server that logs it, and displays changes over time. The system is currently down, so I can provide some sample code, but not a concrete set of working code unfortunately…

2 Likes

You’ve described an architecture but have not provided a purpose or requirements. Start with those and let those drive the architecture decisions.

Answer the “what” and “why” before getting to the “how”.

What is the purpose of the project?
What is the end goal?
Why multiple microprocessors instead of just one?

7 Likes

Very much agreed.

OP, the “it depends” in my prior answers is 100% driven by this - I’m not entirely clear what you’re trying to really accomplish via the setup. The remainder are just sample points to help guide the decision, not actually decisions themselves.

2 Likes

I’m a big fan of RS485, mostly because of my Aerospace jobs, though, it’s a bit tougher to build.

In 2015-2016 I build a trivia button system. The system would have a server and up to 32 “pedestals” hooked to it. I started with I2C on a series of Arduino’s and that worked fairly well, but I needed to span 50feet, and that is where it stopped working, so I switched to RS485. I put the RS485 chip in front of the Arduino UART and that met the speed, length, and multi-drop requirements.

I ended up creating my own printed circuit board, using the processor from the Arduino Uno.

My project notes are here (they are not really organized, it was a place to keep them):
https://drive.google.com/drive/folders/0B5xmD-77SA3DRHpzcnBUSWthOVU?usp=sharing

If you want I can make the schematic of the board public as well.

=Jim

1 Like

Unless you’re trying to achieve very-long distances (already mentioned in another comment), the KISS solution to your goal is to use an I2C bus with 3.3V Arduinos as the slave modules (thereby avoiding all the level-shifting requirements). (The Seeeduino v4.2 is a good example of a Uno-style Arduino-compatible board that supports 3.3V I/O; Adafruit and Sparkfun sell many other Arduino-compatible boards in other form factors that support 3.3V.) The RPi and Arduinos already have all the I2C port hardware and drivers built in, so no further interfacing or conversion hardware cost and complexity are required.
If you need to go more than 10’ to the slaves, use (shielded) twisted-pair wiring for the I2C connection for better noise tolerance; using RS-485 connectors with COTS Ethernet cables is a simple solution for this.
The I2C bus architecture assumes each slave has a preset address. But you could run an I2C port scanner at each boot-up on the RPi to find the connected slaves addresses, thereby eliminating the need for pre-definition of slave address on the master.

1 Like

would that mean I would still have to pre-define the slave addresses?

Yes, you’ll need to pre-define slave addresses. I2C supports 7 bit addresses (that’s 127 unique addresses), so it’s not a significant limitation for small local systems.

1 Like

is there a way to give the slaves a generic address then have the brain give the address to them on first time boot up for the slaves?

You could experiment with that. But I doubt it would work on Arduinos. The critical parts of the program setting up the I2C link on a slave node are shown below. “Wire.begin(8);” sets up the I2C port (with address 8), and “Wire.onRequest(requestEvent);” sets up the required interrupt handler. I’ve never seen these commands placed outside the setup() section of code. There’s also not a Wire.end() command to stop and clear or release the I2C port. You’d need both these capabilities to change the I2C port address and restart communications.

#include <Wire.h>

void setup() {
Wire.begin(8); // join i2c bus with address #8
Wire.onRequest(requestEvent); // register event
}

I suggested I2C as the KISS solution because it only requires 3 wires to communicate. But if you chose the SPI interface instead, you’d need 4-5 wires to each slave but addresses are no longer a factor because it uses the Slave Select wire (unique to each slave node) instead of unique addressing. No address hacking required, with the penalty of at least one additional wire required per slave. Is that a better fit?

1 Like