Project showcase

Senodes © MIT

SNODE – is an open source library that allows to make it easy to build a multi-master serial bus network for hot-plugging nodes with sensors

  • 3,622 views
  • 1 comment
  • 5 respects

Components and supplies

Apps and online services

About this project

SNODE (Sensor Node) is an open source library that allows to make it easy to build a multi-master serial bus network for hot-plugging nodes with sensors.

SENODES is set of hexagonal sensors allows to create various inventions using the SNODE library.

Hardware support

  • Arduino ( Nano, Uno, Micro );
  • CAN controller ( MCP2515 );

IDE

  • PlatformIO

Source code

The full source code could be found here.

Download or Clone the library from GitHub with:

git clone https://github.com/okrutax/senodes.git

Communication between nodes is done over the CAN (Controller Area Network) bus. The CAN bus is a communications protocol which has been around for years as a vehicle bus standard designed to allow nodes to communicate with each other without the need for a host.

In an implementation of SNODE each node could have a few sensors. Each sensor of the node is able to send and receive messages to/from the other sensors of nodes over the CAN bus. This means that a node can have several sensors, each of which can be a master or a slave (the sensor mode type is input or output).

Using the SNODE library simplifies the development process, enabling you to build connected devices in minutes and bring your idea to life.

Hardware Overview

The current SNODE library implementation uses the Microchip MCP2515 CAN controller as the CAN bus controller.

MCP2515 is a stand-alone CAN controller that implements the CAN specification, Version 2.0B. It is capable of transmitting and receiving both standard and extended data and remote frames. The MCP2515 has two acceptance masks and six acceptance filters that are used to filter out unwanted messages, thereby reducing the host MCU’s overhead. The MCP2515 interfaces with microcontrollers (MCUs) via an industry standard Serial Peripheral Interface (SPI).

The CAN network is based on a half-duplex differential signal. CANH is the HIGH-level CAN bus line which is a differential signal. CANL is the LOW-level CAN bus line which is a differential signal. There are two logical states: dominant and recessive. The figure below shows the general concept.

The CAN transceiver is needed to convert the digital signals generated by a CAN controller to signals suitable for transmission over the bus cabling (differential output). It also provides a buffer between the CAN controller and the high-voltage spikes that can be generated on the CAN bus by outside sources (EMI, ESD, electrical transients, etc.).

The Receive (Rx) signal of CAN is the signal receiving the data. The Transmit (Tx) signal of CAN is the signal transmitting the data. These signals are connected to the CAN transceiver (PHY) which performs the CAN encoding and decoding. The CAN bus must be terminated with termination resistors at both ends to avoid electrical signal reflections. Typically, R is 120R. Twisted pair wires in a shielded cable should be used to minimize emissions and reduce interference.

MCP2551 or TJA1055 can be used as the CAN transceiver controller. The typical interconnect schematic diagram of the CAN controller (MCP2515) and the CAN transceiver (MCP2551) is shown below.

The MCU is used to perform the SNODE logic, the CAN and sensors configuration, receive and transmit data, etc.(Figure 1). The Arduino board is used as the MCU of the SNODE implementation.

The following figures are the pin connections of Arduino boards and the popular MCP2512 CAN bus shield.

As the node sensors, there can be any module (OLED, button, buzzer, etc.) connected to the MCU (Arduino) via one of interfaces (SPI, I2C, GPIO, etc.).

Get started

Let’s consider the following example to understand the basic logic of the SNODE Arduino library.

There are three nodes each of which has one or more sensors. Node 1 has three sensors (Button 1, Button 2, Button 3). Node 2 has two sensors (Button and Led). Node 3 has a sensor (RGB Led). The figure below shows the structure of the Node network with sensors.

Each node must be assigned to a unique id as mentioned earlier. In our case, let it be the following IDs: Node ID = 50, Node ID = 60, Node ID =70.

Sensor addresses are automatically assigned during their registration. And their value will be such as those are shown in the figure below.

Task: Three nodes are connected to the same network.

  • Button Sensor = 1 of Node ID = 50 should turn on and off Led Sensor = 2 of Node Id = 60.
  • Button Sensor = 2 of Node ID = 50 should turn on and off Green Led Sensor = 1 of Node Id = 70.
  • Button Sensor = 3 of Node ID = 50 should turn on and off Red Led Sensor = 1 of Node Id = 70.
  • Button Sensor = 1 of Node ID = 60 should turn on and off Blue Led Sensor = 1 of Node Id = 70.

On the picture below with the help of arrows is shown schematic connection between sensors (one sensor is controlled by another) of each of the node.

Note : Node ID = 60 has two types of sensors (input and output). The Led Sensor is output. The Button Sensor is input.

A short video below shows how the SNODE network works.

The following figure is the pin connections of Arduino boards (Nano and Micro), MCP2515 CAN bus shield, Button and Led Modules.

Source Code

The full source code could be found here.

Let’s consider the source code of the example of Node ID 60 (Button and Led Sensors).

Open the snode_one_button example in PlatformIO IDE.

If you want to run the code on another Arduino board, uncomment the necessary one in the file.

The table below shows the pin to pin connection (Arduino Nano, Micro and MCP2515 CAN Bus Shield).

The SNODE library uses the standard SPI interface. Hardware Abstraction Layer (HAL) could be found here.

Add header files:

#include <Arduino.h>
#include "snode.h"

Initialization of the SNODE library and registration of node sensors:

#define CAN_FRAME_SOURCE_ID  (60)

#define SNODE_BUTTON (PD2)
#define SNODE_LED (PD3)

/**************************************************************************/

void setup()
{
Serial.begin(115200);

pinMode(SNODE_BUTTON, INPUT_PULLUP);
pinMode(SNODE_LED, OUTPUT);

SNODE_Init((uint16_t)CAN_FRAME_SOURCE_ID);
SNODE_Registration((PSNODE_SENSOR_REG)&SNODE_Button); //! The Button Address is 0x01.
SNODE_Registration((PSNODE_SENSOR_REG)&SNODE_LedSensor); //! The Led Address is 0x02.
}

The SNODE_Registration function is used to register sensors of the node. The pointer to the SNODE_SENSOR_REG structure is used as the input parameter of the function (const PSNODE_SENSOR_REG pSensor). The struct of the Button Sensor is as follows.

SNODE_ERROR SNODE_GetButtonData(void * data);

/**************************************************************************/

SNODE_SENSOR_REG SNODE_Button =
{
.addr = 0x00,
.type = SNODE_BUTTONS_SENSOR_TYPE,
.mode = SNODE_INPUT_SENSOR_MODE_TYPE,
.subscriber = SNODE_NONE_SENSOR_TYPE,
.callback = SNODE_GetButtonData,
};

/**************************************************************************/

SNODE_ERROR SNODE_GetButtonData(void * data)
{
uint32_t *pButton = (uint32_t *) data;

*pButton = !digitalRead(SNODE_BUTTON);

return SNODE_SUCCESS;
}

The struct of the Led Sensor is as follows.

SNODE_ERROR SNODE_SetLedData(void *data);

/**************************************************************************/

SNODE_SENSOR_REG SNODE_LedSensor =
{
.addr = 0x00,
.type = SNODE_LED_SENSOR_TYPE,
.mode = SNODE_OUTPUT_SENSOR_MODE_TYPE,
.subscriber = SNODE_BUTTONS_SENSOR_TYPE, // Output interface should be subscribed to the other input or control interfaces.
.callback = SNODE_SetLedData,
};

/**************************************************************************/

SNODE_ERROR SNODE_SetLedData(void * data)
{
PSNODE_SENSOR_CALLBACK_DATA pSensorCallbackData = (PSNODE_SENSOR_CALLBACK_DATA) data;

if ( pSensorCallbackData->type & SNODE_BUTTONS_SENSOR_TYPE )
{
if ( 50 == pSensorCallbackData->id )
{
if ( 1 == pSensorCallbackData->addr )
{
if ( pSensorCallbackData->data )
{
digitalWrite(SNODE_LED, HIGH);
}
else
{
digitalWrite(SNODE_LED, LOW);
}
}
}
}

return SNODE_SUCCESS;
}

The SNODE_ProcessPacket function should be called in a loop in order to procedure the SNODE Engine (receive and send frames, multi-frames, timings, etc.).

void loop()
{
SNODE_ProcessPacket();
}

Open the snode_led example in PlatformIO IDE.

Open the snode_buttons example in PlatformIO IDE.

To be continued.

Code

Schematics

MCP2515 Schematic

Comments

Similar projects you might like

Arduino Rotating Platform Based on NEMA17

Project tutorial by Arnov Sharma

  • 2,576 views
  • 0 comments
  • 6 respects

256 Relays!

by Christian

  • 19,683 views
  • 16 comments
  • 60 respects

Too Hot! Too cold! Yes, that's better

Project tutorial by Carlo Russo

  • 2,815 views
  • 0 comments
  • 5 respects

IOTca2

Project in progress by 3 developers

  • 2,310 views
  • 0 comments
  • 4 respects

Arduino Temperature Control

Project tutorial by Team pandhoit

  • 61,803 views
  • 13 comments
  • 56 respects

Multiple ATtiny85/13A Programmer

Project tutorial by Arnov Sharma

  • 2,573 views
  • 0 comments
  • 8 respects
Add projectSign up / Login