Prerequisites
If not already done so already, install Arduino software and make basic connections, as described in page for MRMS ESP32: Arduino, IMU, eFuse, BT, WiFi, CAN Bus (mrm-esp32).
Task
We will read the sensor using CAN Bus to get IR sources's direction and approximate distance).
Hookup
Additionally to the basic hardware connection, as depicted in home page for
MRMS ESP32: Arduino, IMU, eFuse, BT, WiFi, CAN Bus (mrm-esp32), we will connect the sensor,
MRMS IR ball finder 3, CAN Bus, I2C, analog (mrm-ir-finder3).
However, this bus is not only intended for ML-R devices, but for any other CAN Bus compatible. You can read here how to connect Your boards to ML-R CAN Bus.
1. program, raw values
#include <mrm-can-bus.h>
#define COMMAND_IR_FINDER3_SENDING_SENSORS_1_TO_7 0x04
#define COMMAND_IR_FINDER3_SENDING_SENSORS_8_TO_12 0x05
#define COMMAND_SENSORS_MEASURE_CONTINUOUS 0x10
#define COMMAND_IR_FINDER3_SENDING_ANGLE_AND_DISTANCE 0x09
Mrm_can_bus can;
uint8_t data[8]; // Message content: 8 bytes
uint16_t reading[12];
bool near;
void setup() {
Serial.begin(115200);
delay(1000);
data[0] = COMMAND_SENSORS_MEASURE_CONTINUOUS; // First byte of the content
for (uint8_t i = 0; i < 8; i++)
can.messageSend(0x330 + 2 * i, 1, data);
}
void loop() {
uint8_t startIndex = 0;
// Receive a message
CANBusMessage* msg = can.messageReceive();
if (msg != NULL){
uint8_t length = 7;
switch (msg->data[0]) {
case COMMAND_IR_FINDER3_SENDING_SENSORS_1_TO_7:
break;
case COMMAND_IR_FINDER3_SENDING_SENSORS_8_TO_12:
startIndex = 7;
length = 5;
near = msg->data[6];
break;
default:
startIndex = 0xFF;
}
for (uint8_t i = 0; i < length && startIndex != 0xFF; i++)
reading[startIndex + i] = msg->data[i + 1];
}
// Display results
static uint32_t ms = 0;
if (millis() - ms > 500 && startIndex == 7){
for (uint8_t i = 0; i < 12; i++)
Serial.print(reading[i]), Serial.print(" ");
Serial.println(near ? " near" : " far");
ms = millis();
}
}
The program is short, but it hides some of the details in Mrm_can_bus class.
In the beginning, the program declares and defines some variables. Class Mrm_can_bus accesses ESP32s CAN Bus hardware.
Array data is payload CAN Bus messages use. reading array will store measuring results. Variable near indicates if near or far sensors found the target (IR source).
setup() starts serial communication with PC so that Serial.print() can display the results. Further we will use it for an outgoing message and so we set its first byte to COMMAND_SENSORS_MEASURE_CONTINUOUS. That's the command we'd like to execute. It will instruct the sensor to start sending measurement data continually.
As You can have more sensors of this kind in Your CAN Bus, each is supposed to listen to just one message id. The whole range is covered by a loop that follows: 0x330, 0x332,..., 0x33E.
You can change address the sensor listens to but You may not know how the one You have is set up. So, we start them all.
loop() receives messages. When msg pointer is not NULL, a message arrived, so we decode it.
Its first byte determines one of the 2 kinds. The first one carries values of the first 7 sensors and the second one the remaining 5, covering all the 12 sensors.
The latter also contains "near" variable, so we read it, too.
It is not possible to send all the data in one message as its length is limited to 8 bytes. After switch statement, message's payload is loaded into "reading" array. 2 messages set all the reading's values. The last part of the program displays "reading" array and variable "near".
The results are in the picture left. Value 0 means no source detected, 255 is the maximum source strength. When "near" is displayed, near-sensing 12 sensors found the target.
Only when no near-sensing sensor detects the source, 6 far-sensing sensors are engaged. In that case "far" will be displayed and only first of the 12 columns will show the data, again 0-255. If all the columns are 0, no source is detected.
Sensors' positions are depicted left. N are near-sensing sensors and F far-sensing. Numbers next to F and N are columns' ordinal numbers (in the picture). For example, N7 (near-sensing) will be displayed in 7th column and F4 in 4th.
You can use an oscilloscope or a logic analyzer to check the signals.
Using this program, You will get all the raw data and can create Your own algorithm. But what if You are too lazy to do that, or if You are worried that it creates too many messages? In that case, the next example is the right one for You.
2. program, calculated values
#include <mrm-can-bus.h>
#define COMMAND_SENSORS_MEASURE_CONTINUOUS_AND_RETURN_CALCULATED_DATA 0x15
#define COMMAND_IR_FINDER3_SENDING_ANGLE_AND_DISTANCE 0x09
Mrm_can_bus can;
uint8_t data[8]; // Message content: 8 bytes
uint16_t reading[12];
bool near;
void setup() {
Serial.begin(115200);
delay(1000);
data[0] = COMMAND_SENSORS_MEASURE_CONTINUOUS_AND_RETURN_CALCULATED_DATA; // First byte of the content
for (uint8_t i = 0; i < 8; i++)
can.messageSend(0x330 + 2 * i, 1, data);
}
void loop() {
uint8_t startIndex = 0;
// Receive a message
CANBusMessage* msg = can.messageReceive();
if (msg != NULL){
int16_t angle = ((msg->data[1] << 8) | msg->data[2]) - 180;
uint16_t distance = (msg->data[3] << 8) | msg->data[4];
near = msg->data[5];
// Display results
static uint32_t ms = 0;
if (millis() - ms > 500){
Serial.print(angle);
Serial.print(" deg, strength: ");
Serial.print(distance);
Serial.println(near ? " near" : " far");
ms = millis();
}
}
}
You will notice that this program is rather similar to the first one. It uses a different message to instruct the sensor to start sending the (calculated this time) data and message's payload is different. It needs 1 message, not 2 of them.
So, which one is better? If You do not have a special reason to use first, choose this one. If You'd like to have an even simpler solution, check MRMS_ESP32.ino program, which manages messages' interchange automatically.
CAN Bus
The program uses mrm-can-bus library which can be found in C:\Users\<Your login name>\Documents\Arduino\libraries\mrm-can-bus\src. Open mrm-can-bus.cpp in an editor. Notepad++ is a good choice. If You want to change bus speed from the default 250 kbps, find line with "CAN_TIMING_CONFIG_250KBITS" and change the constant. If You like to have messages' content displayed, change "#define VERBOSE 0" into "#define VERBOSE 1". This library is based on Espressif's native driver so Espressif original documentation will give You all the information.
If You use ML-R CAN Bus devices, by far the easiest option for CAN Bus usage will be to stick to the ML-R framework which takes care about messaging so CAN Bus layer is not exposed at all. When You demand MRMS IR ball finder 3, CAN Bus, I2C, analog (mrm-ir-finder3) to return target's direction, You just call a function. The framework takes care that the reasonably fresh result is supplied. The details of this work are not so easy to replicate.
Here is the complete CAN Bus interface:
Command | MCU -> sensor | Sensor -> MCU | Comment |
---|
Firmware | 0x19 | 0x1A LowByte HighByte | Firmware version = (HighByte << 8) & LowByte. |
FPS | 0x30 | 0x31 LowByte HighByte | Frames Per Second (sensor's local loop frequency) = (HighByte << 8) & LowByte. |
Id change | 0x40 NewId | | Changes message's id the sensor listens to. It is close to its address. Valid NewId values are 0 - 7. Each value chooses addresses in the ranges: 0x160, 0x162,..., 0x16E. 0 chooses 0x160, 1 0x162, etc. |
Alive | 0xFF id | 0xFF | If the sensor with address "id" is present, it will return the message. |
Reset | 0x1B | | |
Measure once | 0x11 | 0x13 LowByte HighByte | Measures just once and returns the results, in 2 messages, values for each sensor, as described in the code example above. |
Measure continuously, return each sensor's values | 0x10 | 0x13 LowByte HighByte | Initiates measuring and returning each sensor's values each few ms, if any value changes. Results are returned in 2 messages, as described in the 1. code example above. |
Measure continuously, return calculated values | 0x15 | 0x16 AngleHighByte AngleLowByte DistanceHighByte DistanceLowByte TargetNear | Initiates measuring and returning of calculated values each few ms, if any value changes. Results are returned in 2 messages, as described in the 2. code example above. |
Stop measuring | 0x12 | | |
CAN Bus limitations
For 1 node You will have no problems. If You plan to have many of them, check this page.