Only the orbiter control computer can initiate communications over the construction set bus. It can query various devices on the bus, including Arduino, in points of time specified by the user. It can also receive responses but only for a limited time that can be defined by the user using the function shown below. Therefore every time we want to initiate transfers or receive commands with Arduino there must be an explicit command to perform such an operation in the orbiter program.
The following function invokes commands for interacting with Arduino:
int arduino_send(const uint16_t num, const uint16_t msg_id, char *args, char *answer, char *timeout)
The Arduino side uses a special library orbicraftBus.arduinoLib.zip providing various methods for working with the bus of the construction set.
Description of methods:
Message Receipt Function
When a new message arrives it is written into the msg variable. The function returns message length in bytes (including identifiers), returning 0 when there is no message. -1 will be returned if there was a decoding error.
int16_t takeMessage(Message &msg)
The Message structure contains the following fields:
Message Sending Function
Returns the length of the message sent in bytes.
int16_t sendMessage(const uint16_t address, const uint16_t id, const String data)
Received Data Buffering Function
This method must be called from the serialEvent2() function – see sample code.
void serialEventProcess(void)
Device ID Setting Function
This function is necessary if there are multiple Arduino controllers on the bus.
void setArduinoNumber(const uint8_t newNumber)
newNumber is the new device number.
Function Returning the Device Number
uint8_t getArduinoNumber(void)
If you have not done it yet, take some time to read the Getting Started section where the necessary preparations are explained.
In line with what has become a tradition in Arduino world, our first example will be a program that blinks the built-in LED. This LED is noted as DIR_LED on the shield. It should be noted that a built-in LED connected to pin 13 will also light up on the Arduino board.
Our approach to the use of arduino_send() will be as follows. By merely sending a message ID from the orbiter computer we will invoke an already existing function on the Arduino side implemented in the traditional Arduino way.
Orbiter-Side Code
Here our task is to send a message with an ID that will be used to invoke a function in Arduino.
#include "libschsat.h" void control(void) { /* * Transfer a command for executing command ID 1 to Arduino using the arduino_send built-in function * The first argument is the Arduino ID (defaults to 0) * The second argument is message ID (1 in our case) * The third argument is the data being transferred (NULL as we don’t have any data to send) * The fourth argument is the buffer to receive data (NULL as we don’t expect a response) * The fifth argument is the time to wait for a response from Arduino (100 ms in this case but it matters little in this case as we aren’t waiting for any response) */ arduino_send(0, 1, NULL, NULL, 100); }
Our task is to turn on the built-in LED for 3 seconds by sending a command from the orbiter computer and then turn it off. In order to accomplish that we must receive a packet containing an ID from the orbiter computer and execute the respective command by calling the LED control function.
#include <OrbicraftBus.h> // Import the Orbicraft Construction Set control library /* * Declare the msg variable as the Message data type * Message comprises a structure that contains IDs and transferred message content */ Message msg; /* * Declare the bus variable as the OrbicraftBus data type * OrbicraftBus is a class describing interaction between Arduino and Orbicraft construction set bus */ OrbicraftBus bus; // Declare the msgSize variable to hold the size of the received message uint16_t msgSize = 0; void setup() { Serial1.begin(9600); // Define data transfer rate over Serial1 (Check Serial2.begin(9600)) } void loop() { msgSize = bus.takeMessage(msg); // Try to read the message using the takeMessage method if (msgSize > 0){ //If there is a message… switch (msg.id){//Process in a particular manner depending on message ID // Consider the case with ID 1 case 0x01: turnOnLed(); // Call the function for turning the LED on and off break; } } } void turnOnLed(void){ digitalWrite(LED_BUILTIN, HIGH); //Turn on the built-in LED delay(3000); //Wait 3 seconds digitalWrite (LED_BUILTIN, LOW); //Turn off the built-in LED } /* * The following block of code must always be appended to the program. * The function is called automatically and is necessary for message processing. */ void serialEvent2() { bus.serialEventProcess(); }
Data from Arduino is received by the OCC using the same function on the OCC side:
int arduino_send(const uint16_t num, const uint16_t msg_id, char *args, char *answer)
It works in the same manner as when transferring commands from OCC to Arduino. The only difference is that arduino_send takes other arguments and the respective data to be sent will have to be generated on the Arduino side. For our example we will receive the data from the photoresistive cell (the illuminance sensor) connected to the pin A0 on Arduino. Commented code examples follow.
#include "libschsat.h" void control(void) { char answer[255]; // Create an array to hold the response int32_t count = 5; // Set the counter for 5 steps /* * Transfer a command for receiving the response with ID 2 to Arduino using the arduino_send built-in function * The first argument is the Arduino ID (defaults to 0) * The second argument is message ID (2 in our case) * The third argument is the data being transferred (NULL as we don’t have any data to send) * The fourth argument is the buffer to receive data (in our case it is the array named answer for incoming data) * The fifth argument is the time, in milliseconds, to wait for a response from Arduino (100 ms in our case). */ 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--; } }
#include <OrbicraftBus.h> /* * Declare the msg variable as the Message data type * Message comprises a structure that that describes the identifiers of the message being transferred */ Message msg; /* * Declare the bus variable as the OrbicraftBus data type * OrbicraftBus is a class describing interaction between Arduino and Orbicraft construction set bus */ OrbicraftBus bus; // Declare the msgSize variable to hold the message being transferred int16_t msgSize = 0; // Declare the pin number to sense readings int data_pin = A0; // These pin will be used for readouts from the sensor void setup() { Serial1.begin(9600); // Define data transfer rate over Serial1 (Check Serial2.begin(9600)) } void loop() { msgSize = bus.takeMessage(msg); // Try to read the message using the takeMessage method if (msgSize > 0){ //If there is a message… switch (msg.id){//Process in a particular manner depending on message ID // Consider the case with ID 2 case 0x02:{ String data = String(Sensor_data()); // Store readings obtained from Sensor_data() in the data variable bus.sendMessage(bus.obcAddress, 0, data); // пSend the contents of the data variable to the OCC break; } } } } uint16_t Sensor_data(void){ uint16_t data = analogRead(data_pin); //Read illuminance values from the sensor return data; } /* * The following block of code must always be appended to the program. * The function is called automatically and is necessary for message processing. */ void serialEvent2() { bus.serialEventProcess(); }