Skip to main content

Getting started

Principles of messaging

In the constructor bus, only the on-board control computer can be the initiator of communication over the bus. It can poll various devices on the bus, including the Arduino, at user-specified time points. It can also receive responses, but only for a limited amount of time that the user can assign when using the function described below. Therefore, every time we want to initiate the transmission or receipt of commands to the Arduino, the command for such an operation must be written in the program of the on-board computer.

From the side of the on-board computer

The command to communicate with Arduino is given using the following function:

int arduino_send(const uint16_t num, const uint16_t msg_id, char *args, char *answer, char *timeout)
  • The first argument is the Arduino number (default is 0);
  • The second argument is the message identifier (see which one is needed on the Arduino side, depending on the executable program);
  • The third argument is the transmitted data (if we do not transmit anything, then NULL);
  • The fourth argument is a buffer for the received data (if we are not going to receive anything, then NULL);
  • The fifth argument is the waiting time for a response from Arduino (in ms). Depending on the task being solved, this value must be selected by the user.

From the Arduino side

On the Arduino side, a special orbicraftBus.arduinoLib library is used.zip, which contains various methods for working with the on-board bus of the constructor.

Description of the methods:

Message receiving function

If there is a new message, it is written to the msg variable. The function returns the length of the message in bytes (including identifiers), if there is no message, it returns 0. Returns -1 if there is a decoding error.

int16_t takeMessage(Message &msg)

The "Message" structure has the following fields:

  • from – sender's ID
  • to – recipient's ID
  • id – the message ID
  • data – string of arguments

Message sending function

Returns the length of the transmitted message in bytes.

int16_t sendMessage(const uint16_t address, const uint16_t id, const String data)
  • address – the recipient's address
  • id – the message ID
  • data – string of arguments

The function of writing received data to the buffer

This method should be called from the serialEvent2() function - see the code example.

void serialEventProcess(void)

Device number setting function

It is needed if there are several Arduino on the bus.

void setArduinoNumber(const uint8_t newNumber)
  • newNumber — the new device number.

Function that returns the device number

uint8_t getArduinoNumber(void)
tip

To understand how everything works in the interaction of the OrbiCraft designer and Arduino, you need to study the data transfer protocol [COBS] (https://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing "COBS Data Transfer Protocol") and the basics of object-oriented programming, the terms of which you will find in the code explanations. We highly recommend doing this to understand the principles of the designer's information bus and its interaction with the payload. You will also need basic knowledge of the C/C++ programming language to write code.

If you don't have time to delve into these things at the moment, then you can continue working simply using ready-made programs, or creating new ones in the image and likeness of the provided examples.

Sending commands to Arduino

If you have not done this yet, then first read the section getting ready for work, which describes the necessary preliminary actions.

Traditionally, when working with Arduino, our first example will be flashing the built-in LED. It is marked as DIR_LED on the shield. At the same time, you can notice that the built-in LED connected to the pin also lights up on the Arduino board itself 13 .

Here we use the following approach to using the arduino_send() function. We will only transmit the message identifier from the on-board computer, and on the Arduino side, a ready-made function written in the traditional way for the Arduino environment will simply be called using this identifier.

Code for the on-board computer

Here our task is to send a message with the identifier by which the function will be executed on the Arduino.

tip

You can remember how to create programs for the on-board computer in the [First acquaintance] section (/docs/orbicraft/lessons/first_program).

#include "libschsat.h"

void control(void)
{

/*
* We will send the command to execute the command with the identifier 1 to the Arduino using the built-in arduino_send function
* The first argument is the Arduino number (default is 0)
* The second argument is the message identifier (in this case 1)
* The third argument is the transmitted data (in this case NULL - there is no data to transmit)
* The fourth argument is a buffer for the received data (in this case, NULL - we are not waiting for an answer)
* The fifth argument is the waiting time for a response from Arduino (in this case, 100 ms, but in fact this number does not play a role here, so we are not waiting for an answer)
*/


arduino_send(0, 1, NULL, NULL, 100);

}
``

### Code for Arduino
Our task is to turn on the built-in LED for 3 seconds on command from the [on-board computer](/docs/orbicraft/subsystems/on-board_control_computer) and turn it off. To do this, we must receive a package with an identifier from the on-board computer and execute the appropriate command - to call the function for working with the LED.

:::tip
Don't forget to pre-install the [library] in the Arduino IDE(https://www.arduino.cc/en/guide/libraries "Installing the library") for the interaction of the Arduino and the on-board computer. The library is located in the [required software] section(/docs/orbicraft/instruction_for_working_with_orbicraft/required_software).
:::

```cpp ArduinoTestLed_1_Ard.ino
#include <OrbicraftBus.h> // connecting the library to work with the OrbiCraft constructor

/*
* Declare the msg variable as the Message data type
* Message is a structure containing the identifiers and data of the transmitted message
*/
Message msg;

/*
* Declare the bus variable as the OrbicraftBus data type
* OrbicraftBus is a class describing the interaction of Arduino and the Orbicraft constructor bus
*/
OrbicraftBus bus;

// Declare the msgSize variable, which will record the size of the received message
uint16_t msgSize = 0;

void setup() {
Serial2.begin(9600); // setting the speed of information exchange over Serial2 (test the speed 115200 for new designers 2020)
}

void loop() {
msgSize = bus.takeMessage(msg); // trying to read the message using the takeMessage method
if (msgSize > 0){ //if there is a message
switch (msg.id ){//depending on the message ID, we perform certain actions

// Consider the case of ID 1
case 0x01:
turnOnLed(); // Calling the function to turn on and off the LED
break;
}
}
}

void turnOnLed(void){
digitalWrite(LED_BUILTIN, HIGH); //Turn on the built-in LED
delay(3000); //Waiting for 3 seconds
digitalWrite (LED_BUILTIN, LOW); //Turn off the built-in LED
}

/*
* The following block of code must always be added to the end of the program
* The function is called automatically and is necessary to process the message
*/
void serialEvent2() {
bus.serialEventProcess();
}

Getting data from Arduino

Data is received from the Arduino to the BCU using the same function on the BCU side:

int arduino_send(const uint16_t num, const uint16_t msg_id, char *args, char *answer)

The essence of the work is the same as when transferring the command from the control unit to the Arduino. Only other arguments of the arduino_send function are used for operation, and accordingly, data needs to be generated for transmission on the Arduino side. For example, we will take values from a photoresistor (light sensor) connected to the pin A0 Arduino. Code examples with explanations are provided below.

danger

Before connecting the photoresistor to the Arduino, see how it is done correctly. The photoresistor can be used as a separate element with the necessary peripherals, or it can be in the form of a ready-made module with a ready-made binding.

Code for the on-board computer

``cpp ArduinoTestLightSensor_1_Orbi.c #include "libschsat.h"

void control(void) { char answer[255]; // Creating an array to save the answer int32_t count = 5; // Setting the counter to 5 steps /*

  • We will send a command to receive a response with the identifier 2 to the Arduino using the built-in arduino_send function
    • The first argument is the Arduino number (by default 0)
  • The second argument is the message identifier (in this case 2)
  • The third argument is the transmitted data (in this case NULL - there is no data to transmit)
      * The fourth argument is a buffer for the received data (in this case, answer is an array for storing the received data)
  • The fifth argument is the waiting time for a response from Arduino in ms (in this case, 100 ms) */ while (count > 0){ int status = arduino_send(0, 2, NULL, answer, 100); if (status == 0){ printf("Answer: %s\r\n", answer); } else{ printf("Error\r\n"); } mSleep(500); count--; }
    }

### Code for Arduino

```cpp ArduinoLightSensor_1_Ard.ino
#include <OrbicraftBus.h>

/*
* Declare the msg variable as the Message data type
* Message - is a structure describing the identifiers of the transmitted message
*/
Message msg;

/*
* Declare the bus variable as the OrbicraftBus data type
* OrbicraftBus is a class describing the interaction of Arduino and the Orbicraft constructor bus
*/
OrbicraftBus bus;

// Declare the msgSize variable, into which the transmitted message
int16_t msgSize = 0 will be written;
// Let's declare the pin number for reading
int data_pin = A0; // Specify the pin from which we will read the sensor readings

void setup() {
Serial1.begin(9600); // setting the speed of information exchange over Serial2 (test the speed 115200 for new constructors 2020)
}

void loop() {

msgSize = bus.takeMessage(msg); // trying to read the message using the takeMessage method

if (msgSize > 0){ //if there is a message
switch (msg.id ){//depending on the message ID, we perform certain actions

// Consider the case of ID 2
case 0x02:{
String data = String(Sensor_data()); // writing the readings received from the Sensor_data() function to the data variable
bus.SendMessage(bus.obcAddress, 0, data); // passing the contents of the data variable to the database
break;
}
}
}
}

uint16_t Sensor_data(void){
uint16_t data = analogRead(data_pin); //Reading the light readings from the sensor
return data;
}

/*
* The following code block must always be added to the end of the program
* The function is called automatically and is necessary to process the message
*/
void serialEvent2() {
bus.serialEventProcess();
}