Technology Careers Contact
Documentation Community Download Support

Welcome to Luos documentation

Introduction

We started designing Luos with the conviction that building electronic systems should be made easier than it is today. Most of the time should be spent on designing the applications and behaviors instead of on complex and time-and-money-eating technicalities. To give a simple example, adding a new sensor —for instance a distance sensor— to an electronic device in conception should not take more than a few minutes. So you can try, test and iterate fast on a project to truly design what users want.

Luos works like microservices architecture in the software world, and a distributed operating systems: it encapsulates any software or hardware function to make it communicate and work with any other encapsulated module, however it was developed, either on bare metal or on top of an embedded OS.

You are not familiar with Luos operations? Follow this flowchart:

If you have questions about a specific topic, you can refer or ask it on the Luos' Forum. And if you have suggestions about this documentation don't hesitate to create pull requests.

Watch this video for additional details:


Luos is free for non-commercial use. It's protected by a license that you can consult here.

General guide to Luos technology

Luos is a simple and lightweight distributed operating system dedicated to embedded systems enabling microservices architecture for electronics. It's a powerful tool using modularity to simplify and link any hardware component or application code together as a single system image.

This guide contains all the basic notions you will need to use, create and understand Luos technology.

Luos is a low-level software technology uploaded into every board's (nodeHardware element (MCU) hosting and running Luos and hosting one or several modules.) of a device. You can use Luos as a bare metal lib or as a driver into your embedded OS.

Luos is composed as well of code subdivisions called modulesSoftware element run by Luos that can communicate with other modules. Can be driver or app.. Modules are distributed into every nodes in a network.

What is a Node

A node is a physical component (hardware) running Luos and hosting one or several modules. In a Luos network, nodes are all connected together using RobusCore communication bus used by Luos to detect and communicate with modules in a network., the Luos communication technology.
In other words, a node is a microcontroler connected to other microcontrolers running Luos. In the Luos philosophy, each node has to carry the necessary programs (modules) allowing it to manage its boards and features.

Nodes can have capacities such as measuring the core temperature, sending the processor's unique ID or input voltage. A node's capacities are commonly shared by all the modules hosted into it and are accessible through each of them.

Module

A module is a block of code which is able to communicate with any other modules through the Luos network. Each module provides an API allowing to manage a motor, handle a laser range finder, or compute an inverse-kinematics, for example. Each module is hosted in a single node, but a node can handle several modules at the same time and manage communication between them and between other modules hosted in other nodes, using the same interface.

For example, the Dynamixel board provided by Luos can dynamically create and manage Dynamixel modules depending on the number of Dynamixel motors linked to it. Any Dynamixel modules can get or set values to other Dynamixel modules on the same node or to any other modules in any other nodes in the network.

Go to Modules page.

Messages

All modules can share and receive datas using messages.

Go to Messages handling page.

Routing table

A routing table is a "service" managed by the Luos network and available for any modules in any nodes. This service lists all the modules and allows to any modules to get and use basic information of any other modules. The routing table's data can be loaded or auto-generated during detection.

Go to Routing table page.

Module detection

The module detection assigns IDs to modules depending on their node's physical position in the network, and generates a routing table.

IDs are assigned from the nearest to the furthest node branch by branch, from the point of view of the module running the detection. Following this logic, the module running the detection will have the ID 1, the next one will have the ID 2, etc.

Note: Multiple detection by different modules at the same time is not allowed.

It's possible to detect the network frequently in order to dynamically discover included or excluded modules while running. Go to Routing table page for more informations.

Low level

This part of the Luos documentation is dedicated to people designing their own electronic boards or their specific embedded code.

Let's start by setting up your development environment, then you can start your electronic design and your modules creation.

Setup your development environment

Before starting developing with Luos, you need to have an operational development environment. At Luos, we use PlatformIO to share all our examples and to make our lib integration easy, but of course you can use your favorite IDE and integrate our libs by yourself.

Setup a Luos PlatformIO project

PlatformIO is a cross-platform, cross-architecture, multiple framework, professional tool for embedded systems engineers and for software developers who write applications for embedded products. You can put it as a plug-in in a lot of different editors.

Getting Started

  1. Install Platform IO on VSCode by following the instructions on this page.
  2. Create a new projet on PlatformIO
  3. Add Luos as dependancy and select HAL on your platformio.ini file:
lib_deps = Luos
board = <board name>

Replace <board name> with the name of the board you're using, eg. board = l0 for the L0 board.

Note: More information about how Luos libs are managed into PlatformIO is available by following this post on our forum.

Project examples

Luos shares a lot of code examples, feel free to use and modify them as you want.

Prototyping boards

Luos created a sets of boards allowing to easily prototype a device.

General integration consideration

Luos works as a library. Our technology is constituted of 2 libs:

To make it work on your environment, you have to:

  • Include both lib folders (Robus and Luos) in your project compilation,
  • Select the good hal folder to use, depending on you hardware,
  • Include Luos.h on your source file.

Integrating Luos into an electronic board

Luos uses RobusCore communication bus used by Luos to detect and communicate with modules in a network. to communicate with other boards. To design your board, you have to understand that Robus needs to adapt to your own design. Electronic boards must respect some design rules in order to properly work in a Luos network.

Electronic design

Board examples and electronic sources are available on GitHub. You are free to use them as you want.

The basic version of Robus uses RS485, but you can use any Half duplex support allowing to check transmitted data.

Here is the example of the schematic of L0 boards (available on GitHub).

A Luos-friendly electronic board must contain at least the following elements:

  • 1 MCU (microcontroller unit): It hosts, as a node, the Luos firmware along with the different modulesSoftware element run by Luos that can communicate with other modules. Can be driver or app. (drivers and apps).
  • At least 2 connectors: They allow to link boards together into a Luos network (Luos' official connector is: DF11-8DP-2DS(24)).

Compatible MCUs

Luos manages any type of microcontrollers, but they need to be added manually to the library. If your microcontroller is not managed yet, please contact us:

  • by mail: contact@luos.io
  • on GitHub

Modules

A module is a block of code which is able to communicate with any other modules in the Luos network.

A module can be an application or a driver.

Each module provides a particular set of tasks such as managing a motor, handling a laser range finder, or compute an inverse-kinematics. Each module is hosted in a single nodeHardware element (MCU) hosting and running Luos and hosting one or several modules. (MCU), but a node can handle several modules at the same time and manage communication between them and between other modules hosted in other nodes, using the same interface.

As a developer you will always develop your functionalities into modules, and never into the main() program. The only information that should be put on the main() code are MCU setup parameters and modules' run functions.

Module properties

To properly work, each module owns some properties allowing to other modules to recognize and access it:

NameDescriptionFormat
IDThe ID is a unique number given to each module depending on their physical position. The system automatically assigns each ID during the detection phase. If you move a module from a microcontroller A to a microcontroller B on a given device, the ID will change. In the same way, if you change the wiring order of a microcontroler on the network on a given device, the ID will change too.Integer
e.g. Id=1
TYPEThe type defines the module purpose. A few types are predefined and can be used, or new ones can be created. The module type can't be changed after module initialization.String
e.g. type=DISTANCE_MOD
ALIASAlias is the name of the module. It's used to easily identify a module. Each module has a default alias which can be changed by users. For example, a module with the default alias motor_mod can be named left_knee_motor by user. This new name will be stored in the non-volatile memory of the board. As we don't want to have multiple modules with the same name, a duplicate name on your system will be automatically assigned with an incrementing number at its end, in the network. You can go back to the default name by setting a void name ("") to a module.String
e.g. alias="gate"

Create Luos Projects

How to properly organize your Luos projects

How to run Luos

Luos is like a task that has to be run regularly. So you will have to run it by adding luos_init() and luos_loop() in the main() of your program.
Basically, your main() will look like this:

#include "luos.h"

int main(void)
{
    luos_init();
    while(1)
    {
        luos_loop();
    }
    return 0;
}

Putting this code into a nodeHardware element (MCU) hosting and running Luos and hosting one or several modules. makes it able to react to a Luos network. It's now ready to host your modules.

As a developer you will always develop your functionalities into modules and never into the main() program.

Note: The only information that should be put on the main() code are MCU setup parameters and modules' run functions.

How to add modules in your project

A node can host multiple modules, and a module has to be as portable as possible. In order to do that, modules have to be independent code folders that can be easily copied and pasted in another project.
To make it at Luos we always use the same way to organize our projects: we put the modules into a modules folder and name the modules' code files with the name of each module:

 Project
    │
    ├─── modules
    │    ├─── module_1
    │    │    ├─── module_1.c
    │    │    └─── module_1.h
    │    └─── module_2
    │         ├─── module_2.c
    │         └─── module_2.h
    │
    ├─── Inc
    │    ├─── Luos
    │    └─── Robus
    │
    └─── Src
         └─── Main.c

Basic modules functions

We choose to put the public functions of our modules in the module.h file. Like Luos, modules are similar to tasks that need to be run regularly, so we choose to use the exact same stategy as presented for Luos functions by providing a module_init() and a module_loop() functions and to add them in the main(). Following the previous folder organization, the main() code looks like this:

#include "luos.h"
#include "module_1.h"
#include "module_2.h"

int main(void)
{
    luos_init();
    module_1_init();
    module_2_init();
    while(1)
    {
        luos_loop();
        module_1_loop();
        module_2_loop();
    }
    return 0;
}

This way, it is easy to manage all your modules and to add as many of them in the main() file as you want.

Create Luos modules

As a developer you will always develop your functionalities into modules and never into the main() program.

Warning: Make sure to read and understand how to Create Luos projects before reading this page.

How to create and initialize a module

To create a module, you have to call this function:

module_t* luos_module_create(void* callback, module_type_t type, char* default_alias, char* firm_revision);

The returned module_t* is a module structure pointer that will be useful to make your module act in the network after this initialization.

callback is a pointer to a callback function called by Luos when your module receive messages from other modules (see Real-time configuration page for more details). This function needs to have a specific format:

void module_cb(module_t *module, msg_t *msg)
  • module is the module pointer of the module receiving the data (basically, it is your module).
  • msg is the message your module received.

type is the type of the your new module represented by a number. Some basic types (e.g. DISTANCE_MOD, VOLTAGE_MOD, etc.) are already available in the module_type_t enum structure of Luos. You can also create your own on top of the luos one.

default alias is the alias by default for your new module. e.g. MyModule02. This alias is the one your module will take if no other alias is set by the user of your functionality hosted in your module. Aliases have a maximum size of 16 characters.

firm_revision is the version number of the module you are creating and which will be accessible via pyluos.

Following the project rules, here is a code example for a button module:

module_t* module_btn;

void rx_btn_cb(module_t *module, msg_t *msg){
    // Manage received messages
}

void button_init(void) {
	//STRINGIFY (VERSION) is used to get the module version in the module's library.json file
    module_t* module_btn = luos_module_create(rx_btn_cb, STATE_MOD, "button_mod", STRINGIFY(VERSION));
}

void button_loop(void) {
}

Note: According to the real-time configuration you chose, an additional line of code may be necessary. See Real-time configuration page for more details.

Modules categories

To make your development as clean as possible, you have to understand in which category (Driver or App) each module of the project is.

By following the categories guidelines, you will be able to make clean and reusable functionalities.

Drivers guidelines

A driver is a type of module that drives hardware. Motors, distance sensors, LEDs are all drivers.

By designing a driver, you have to keep the following rules in mind:

  • A driver module always uses a standard Luos type to be usable by any other modules.
  • A driver module always uses standard object dictionarySet of objects based on SI metric system that can be transmitted through Luos messages. Any object can easily be converted in other units. structures to be usable by any other modules.
  • A driver module never depends or uses any other modules (driver or app).
  • A driver module is "dumb", as it can't do anything else than manage its hardware feature (but it does it very well).

You can have multiple driver modules on the same nodeHardware element (MCU) hosting and running Luos and hosting one or several modules. managing different hardware functionalities of your board, it is your call to sort them depending on your design.

Apps guidelines

An applications or app is a type of module that only manages software items such as functions or algorithms. Apps use other modules to make your device act, operate, and behave. Apps can be placed in any nodesHardware element (MCU) hosting and running Luos and hosting one or several modules. on a Luos network without any hardware or code modifications. However, the choice of the hosting node can impact global performances of the system.

By designing an app, you have to keep the following rules in mind:

  • An app can't have hardware dependencies.
  • An app can use custom module types.
  • An app must use standard object dictionarySet of objects based on SI metric system that can be transmitted through Luos messages. Any object can easily be converted in other units. structures. If the structures used are not standard, Gate modules could be completely unable to manage them.

Apps are the embedded smartness of your device, and at least one of them should run a network detection in order to map every modules in every nodes in your device and make it work properly. Go to Routing table page for more informations.

Object Dictionary

To keep interoperability between modulesSoftware element run by Luos that can communicate with other modules. Can be driver or app., Luos provides an Object Dictionary (OD).

What is OD?

An Object Dictionary (OD) allows different developers of different modules to make them interoperate regardless of the unit they uses on the module.

Let's take an example: If module1 uses an angle as radians and module2 uses degrees, what is the unit they should use to share the angle information?

An Object Dictionary defines a set of typical objects that can be transmitted through Luos messages. It allows to send these objects with a predefined type and to use it in the units the user want.

How is it managed in Luos?

Luos defines objects based on physical values following the SI standard.

Object and types

Each object in the Object Dictionary has a specific Type. For example:

// Define object angular_position as an angular_position_t type
angular_position_t angular_position; 

You can create your variables using these objects but never set OD variables directly with a value. Instead, you have to use functions available on the Luos OD:

// Set object angular_position
angular_position_t angular_position = angular_position_from_deg (12.0); 

Following this rule, everybody will be able to use your values.

All the types are listed in the table summary at the end of this page.

Conversions

As many units exist, many conversion functions are available. As a result, they follow a logic naming rules in order to easily find a desired function without having to search for it.

Unit conversions

There are two types of unit conversion: in one way (OD type from desired unit), and in the other way (OD type to desired unit):

  • from conversion: Converts a value with a defined unit into a desired OD type. Format: [type_var] = [type]_from_[unit]([value])
// save a linear_position from a mm value
linear_position_t linear_position_from_mm(float mm); 
  • to conversion: Converts a type to a unit. Format: [value] = [type]_to_[unit]([type_var])
// convert the variable linear_position into a mm
float linear_position_to_mm(linear_position_t linear_position); 

Messages conversions

The same both way of conversion are available for messages (OD type from message and OD type to message):

  • from conversion: Gets a type from a message. Format: [type]_from_msg([type_var], msg)
// get the linear_position from the message msg
void linear_position_from_msg(linear_position_t* linear_position, msg_t* msg); 
  • to conversion: Inserts a desired type into a message. Format: [type]_to_msg(type_var], msg)
// insert the linear_position into the message msg
void linear_position_to_msg(linear_position_t* linear_position, msg_t* msg);

Types and units table summary

Here are listed the existing types:

TypeAvailable prefix and other units
linear_positionnm, μm, mm, cm, m, km, in, ft, mi
linear_speedmm/s, m/s, km/h, in/s, mi/h
angular_positiondeg, revolution, rad
angular_speeddeg/s, revolution/s, revolution/min, rad/s
forceN, kgf, ozf, lbf
momentN.mm, N.cm, N.m, kgf.mm, kgf.cm, kgf.m, ozf.in, lbf.in
voltagemV, V
currentmA, A
powermW, W
ratiopercentage
temperaturedeg_c, deg_f, deg_k
color8bit_RGB unsigned char [3]

Note: to find out a conversion function, replace the characters / or . in the units by the character _. The character µ is replaced by u, and revolution is replaced by rev.

Examples: convert a linear speed to mm/s: linear_speed_to_mm_s(); convert a value in μm to a linear position: linear_position_from_um(); convert a value in revolutions/s to an angular speed: angular_speed_from_rev_s();

Routing Table

Warning: Make sure to read and understand how to Create Luos modules before reading this page.

The routing table is a feature of Luos allowing every modulesSoftware element run by Luos that can communicate with other modules. Can be driver or app. to own a "map" (or topology) of the entire network of your device. This map allows modules to know their physical position and to search and interact with other modules easily.
This feature is particularly used by apps modules to find other modules they need to interact with.

Detection

Routing tables are automatically generated and shared to all modules by network detections. A detection can be initiated by any module, but driver modules should not be able to run it and this kind of features should be only used on app modules.

To run a detection, type:

detect_modules(app);

where app is the module_t pointer running the detection.

A non-detected module (not in the routing table) has a specific ID of 0. At the beginning of the detection, Luos erases each module's ID in the network, so all of them will have the ID 0 during this operation. You can use it on your modules code to act consequently to this detection if you need it (for example, a module can monitor its ID to detect if a detection has been made and if it has to reconfigure its auto-update).

Then the module running the detection will have the ID 1 and the other modules will have an ID between 2 and 4096, depending on their position from the module detector. The IDs are attributed to the modules according to their position from the detector module and to the branch they are in. The ID attribution begins first to the PTPA port, then PTPB, etc. When each module in the network has an attributed ID, the detection algorithm proceeds to the creation of the routing table and shares it with every modules (saved only one time per node).

Sometimes, multiple modules in the network can have the same alias, which is not allowed to prevent module confusion. In this case, detection algorithm will add a number after each instance of this alias on the routing table.

Warning: Be careful that during a detection, a module can change ID depending on the module running this detection. Do not consider your module's ID fixed. Also, be aware that every modules remove their auto-update configuration during the detection to prevent any ID movement.

Modes

As explained in this page, nodesHardware element (MCU) hosting and running Luos and hosting one or several modules. can host multiple modules. To get the topology of your device, the routing table references physical connexions between your nodes and lists all the modules in each one of them.

The routing table is a table of a routing_table_t structure containing nodes or modules information. The maximum number of modules and nodes are managed by the precompilation constant MAX_MODULES_NUMBER (set to 40 by default).

route_table_t route_table[MAX_MODULES_NUMBER];

The routing table structure has two modes: module entry mode and node entry mode.

typedef struct __attribute__((__packed__)){
    entry_mode_t mode;
    union {
        struct __attribute__((__packed__)){ // MODULE entry mode
            unsigned short id; // Module ID
            unsigned char type; /*!< Module type. */
            char alias[MAX_ALIAS_SIZE]; /*!< Module alias. */
        };
        struct __attribute__((__packed__)){ // NODE entry mode
            luos_uuid_t uuid; // Node UUID
            unsigned short port_table[4]; // Node link table
        };
    };
}routing_table_t;

Module entry mode

This mode allows route_table to contain:

  • id: module's unique id
  • type: module's type
  • alias: module's alias

For more information, please refer to the Modules page of this documentation.

Node entry mode

This mode gives physical information of your devices.

The uuid is the serial number of the microcontroler hosting Luos. This number is unique, you can use it to identify each one of your nodes.

The port_table allows to share topological information of your network. Each element of this table corresponds to a physical Luos port of the node and indicates which node is connected to it by sharing a module's id.

Here is an example:

As shown on this image, elements of the port_table indicate the first or last module id of the connected node through a given port.

Specific values taken by port_table:

  • 0: this port is waiting to discover who is connected with. You should never see this value.
  • 0x0FFF: this port is not connected to any other Node.

Note: Routing tables can be easily displayed using Pyluos through a USB gate. Please refer to the Pyluos routing table section for more information.

Search tools

The routing table library provides the following search tools to find modules and nodes' information into a Luos network:

DescriptionFunctionReturn
Find a module's id from its aliasid_from_alias(char* alias);int
Find a module's id from its type (return the first of the list)id_from_type(module_type_t type);int
Find a module's string from its type (return the first of the list)string_from_type(module_type_t type);char*
Find a module's alias from its id (return the first of the list)alias_from_id(uint16_t id);char*
Find a module's type from its idtype_from_id(uint16_t id);module_type_t
Find a module's type from its aliastype_from_alias(char* alias);module_type_t
Test if a module's type is a sensoris_sensor(module_type_t type);uint8_t
Get a node's idget_node_id(unsigned short index);int
Get the number of nodes in a Luos networkget_node_nb(void);int
Get the list of all the nodes in a Luos networkget_node_list(unsigned short* list);void

Management tools

Here are the management tools provided by the routing table library:

DescriptionFunctionReturn
Compute the rooting tablecompute_route_table_entry_nb(void);void
Detect the modules in a Luos networkdetect_modules(module_t* module);void
Convert a node to a routing table entryconvert_board_to_route_table(route_table_t* entry, luos_uuid_t uuid, unsigned short* port_table, int branch_nb);void
Convert a module to a routing table entryconvert_module_to_route_table(route_table_t* entry, module_t* module);void
Insert an entry into the routing tableinsert_on_route_table(route_table_t* entry);void
Remove an entry in the routing table (by id)remove_on_route_table(int id);void
Erase routing tableflush_route_table(void);void
Get the routing tableget_route_table(void);route_table_t*
Get the last module in a Luos networkget_last_module(void);int
Get the last entry in a Luos networkget_last_entry(void);int

Modules communication is based on messages

Warning: Make sure to read and understand how to Create Luos modules before reading this page.

As a developer, you will have to create and use Luos messages to exchange informations between modulesSoftware element run by Luos that can communicate with other modules. Can be driver or app.. In order to do that, you have to understand how messages works.

Message structure

Luos messages are managed by the msg_t structure:

typedef struct{
    header_t header;
    unsigned char data[MAX_DATA_MSG_SIZE];
}msg_t;

All messages have a header. A header is a 7-byte field containing all information allowing modules to understand messages context. All modules on the network catch and decode the header of each sent and received message.

data is a table containing informations.

Info: MAX_DATA_MSG_SIZE represenst the maximum size of messages (default value is 128 bytes);

Header

To send data to any modules you want, you will have to fill some information on the header.

here is the header_t structure:

typedef struct{
    unsigned short protocol : 4;       /*!< RESERVED Protocol version. */
    unsigned short target : 12;        /*!< Target address, it can be (ID, Multicast/Broadcast, Type). */
    unsigned short target_mode : 4;    /*!< Select targeting mode (ID, ID+ACK, Multicast/Broadcast, Type). */
    unsigned short source : 12;        /*!< Source address, it can be (ID, Multicast/Broadcast, Type). */
    unsigned char cmd;                 /*!< msg definition. */
    unsigned short size;                /*!< Size of the data field. */
}header_t;
  • Protocol (4 bits): This field provides the protocol revision. This field is automatically filled, you don't have to deal with it.
  • Target (12 bits): This field contains the target address. Make sure to understand the real destination of this field, you have to know the addressing mode contained on the Target_mode field.
  • Target_mode (4 bits): This field indicates the addressing mode and how to understand the Target field. It can take different values:
    • ID: This mode allows to communicate with a unique module using its ID without acknowledgment return.
    • ID_ACK: This mode allows to communicate with a unique module using its ID with acknowledgment return.
    • Multicast/Broadcast: This mode allows multiple modules to catch a message. In this case, the message contains a type of data used by multiple modules.
    • Type: This mode sends a message to all modules with a given type, for example all "Sharp digital distance sensor".
  • Source (12 bits): The unique ID of the transmitter module.
  • CMD (8 bits): The command defines the transmitted data's type.
  • Size (16 bits): Size of the incoming data.

Receive and send a basic message

To send a message you have to:

  1. Create a message variable
  2. Set the target_mode
  3. Set the target
  4. Set the cmd
  5. Set your data size
  6. Set your data
  7. Send it.

Here is a basic reply example that you can find in a module reception callback:

void modules_cb(module_t *module, msg_t *msg) {
    if (msg->header.cmd == ASK_PUB_CMD) {
        // fill the message info
        msg_t pub_msg;
        pub_msg.header.target_mode = ID;
        pub_msg.header.target = msg->header.source;
        pub_msg.header.cmd = IO_STATE;
        pub_msg.header.size = sizeof(char);
        pub_msg.data[0] = 0x01;
        luos_send(module, &pub_msg);
        return;
    }
}

Module exclusion

Luos includes an acknowledgement management using the ID_ACK target_mode. This mode guaranties the proper reception of critical messages.

If Luos fails to reach its target using ID_ACK, it will retries 10 times. If the acknowledgement still fails, the targeted module is declared excluded. Excluded modules are removed from the routing table to avoid any messaging by any modules, preserving bandwidth for the rest of the system.

Large data

You will sometimes have to deal with large data that could be larger than the maximum 128-byte data on a Luos message. Fortunately, Luos is able to automatically fragment and de-fragment the data above this side. To do that, you will have to use another send function that will take care of setting the messages' size, and the data fields.

For example, here is how to send a picture:

// fill the large message info
msg_t msg;
color_t picture[300*300] = {/*Your favorite cat picture data*/};
msg.header.target_mode = ID_ACK;
msg.header.target = 12;
msg.header.cmd = COLOR;
luos_send_data(module, &msg, picture, sizeof(color_t)*300*300);
return;

In the reception callback, here is the code for retrieve the message with the receiving module (the one with ID 12):

color_t picture[300*300];
void modules_cb(module_t *module, msg_t *msg) {
    if (msg->header.cmd == COLOR) {
        luos_get_data(module, msg, (void*)picture);
    }
}

Note: If you have to deal with high-frequency real-time data, please read the Streaming page.

Time-triggered update messages

Luos provides a standard command to ask a module to retrieve values from a sensor, called ASK_PUB_CMD. However, sometimes apps need to poll values from sensors, but the act of repeatedly retriving a value using the ASK_PUB_CMD command may result in the use of a lot bandwidth and take useless resources. In this kind of polling situation, you can use the time-triggered auto-update features available from any Luos module. This feature allows you to ask a module to send you an update of any value each X milliseconds. To use it, you have to setup targeted module with a message containing a standard time object dictionarySet of objects based on SI metric system that can be transmitted through Luos messages. Any object can easily be converted in other units., but with a specific command associated to it.

For example, to update a module each 10ms:

time_luos_t time = time_from_ms(10);
msg_t msg;
msg.header.target = id;
msg.header.target_mode = IDACK;
time_to_msg(&time, &msg);
msg.header.cmd = UPDATE_PUB;
luos_send(app, &msg);

Info: Modules can handle only one time-triggered target, 2 modules of the same network can't ask a time-triggered value from the same module.

Warning: To prevent any ID movement, auto-update configuration is reseted on all modules at each detection (see Routing table page for more information).

Streaming

In occasion, you will have to deal with high-frequency small data with strong time constraints.

To make it easy, Luos manages streaming channels trough ring buffers.

A streaming channel allows you to reduce drastically the time constraints of your Luos network thanks to 2 effects:

  1. The first effect is a method which allows you to have a no-real-time module dealing with a strict-real-time one. Both side have their own loop frequency and time precision.

    • The real-time one is the module opening the streaming channel. It has a high-frequency function called at a precise sampling frequency.
    • The no-real-time one has a slower and unprecise timed function which is called at each chunk_time.
  2. By using streaming channels, you will be able to use big data chunks at low frequency to optimize the data rate efficiency of the bus. The idea is to exchange big chunks of data between modules instead of a tons of time-constrained small messages flooding all modules.

Example

A motor-driver module has strict real-time constraints. If you want to have a smooth positioning movement or measurement you have to update the motor position at high-frequency (sampling frequency).
First, you have to define the sampling frequency allowing you to have a smooth movement or measurement on the motor. Let's take 200Hz in this example.

In the no-real-time side (the module commanding the motor), you can't have a 200Hz loop because it probably has other things to do and perhaps doesn't have a sufficient time precision. To simplify it you will have to send trajectory chunks regularly (chunk time), let's say approximately each 1 second.

Based on those numbers, your data chunk size will be:

chunk_size = chunk_time(s) x sampling_frequency(Hz)
chunk_size = 1 x 200 = 200 samples

In our configuration, data chunk needs to be 200 position samples each second, allowing to feed the streaming channel.

Following our example, if we want to send trajectory to the motor, we will have a ring buffer in the motor side managed by the streaming channel. Here are the different states of this ring_buffer:

  1. The module who sends the trajectory has to make sure that the motor module always has data to consume. To do that you have to bootstrap your streaming flux by sending 2 data chunks to start and then send a new data chunk each chunk_time. This way, receiver always has at least one data chunk (1s in this example) ready to be consumed.
  2. When data chunks are received, receiver can start consuming data at its sampling frequency.
  3. One data chunk later (1s in our example), receiver has consumed the first data chunk, and the sender can start to compute the next one.
  4. At the end of the data chunk computation, sender sends the chunk. Luos adds it to the ring buffer.
  5. At each second, the sender sends the next data chunk and Luos add it to the ring buffer. At the end of the buffer, Luos puts extra data at the begining. The consumer pointer also goes back to the begining of the buffer when it reaches the end. This way we have infinite data stream without any discontinuity.
  6. You can continue this way indefinitely.

Note: You can play pause, stop or record stream flux with the standard CONTROL command using the control_type_t structure.

How to use it

A streaming channel is always created by the strict real-time module. The other module (the no-real-time one) will just send or receive its data chunks using large data messages.

Streaming channel creation

Before starting using streaming method, you have to create a streaming channel linked to a buffer into the init function of your real-time module:

#define BUFFER_SIZE 1024
volatile angular_position_t trajectory_ring_buf[BUFFER_SIZE];
streaming_channel_t trajectory;

void motor_init(void) {
    trajectory = create_streaming_channel(trajectory_ring_buf, BUFFER_SIZE, sizeof(angular_position_t));
    luos_module_create(rx_mot_cb, CONTROLLED_MOTOR_MOD, "motor_mod");
}

Now you can use this channel to receive or transmit a streaming flux:

  • reception is adapted to make our motor move smoothly. A no-real-time module will send us parts of trajectory approximately each second and our motor will consume angular position at 200Hz.
  • transmission is adapted to measure precisely the movements of the motor. We can use it to send in a no-real-time way real-time data. In our motor it could be angular position measurement at 200Hz for example.

Streaming reception

This is used to make the motor move.
When your streaming channel has been created, you can feed it with received messages on your reception callback:

void rx_mot_cb(module_t *module, msg_t *msg) {
   // check message command
   if (msg->header.cmd == ANGULAR_POSITION) {
       // this is our trajectory reception
       luos_receive_streaming(module, msg, &trajectory);
   }
}

Now your module is able to receive trajectory chunks. For the next step, you need to have a real-time callback (using a timer for example) which is able to manage the consumption of this trajectory at 200hz:

void 200hz_callback(void) {
    get_sample(&trajectory, &motor.target_angular_position);
}

Streaming transmission

This is used to measure the motor movements.
To go the other way and send a sampled signal such as a position measurement, you have to use your streaming channel in reception. First you have to put values into your streaming channel at 200Hz:

void 200hz_callback(void) {
    set_sample(&trajectory, &motor.angular_position);
}

This way, samples are buffered into your ring buffer, and you can send this real-time information as you want. For example only when someone ask you to:

void rx_mot_cb(module_t *module, msg_t *msg) {
   msg_t pub_msg;
   // check message command
   if (msg->header.cmd == ASK_PUB_CMD) {
       // prepare a reply message and send
       pub_msg.header.target_mode = ID;
       pub_msg.header.target = msg->header.source;
       pub_msg.header.cmd = ANGULAR_POSITION;
       luos_send_streaming(module, &pub_msg, &measurement);
   }
}

The luos_send_streaming function sends data available on your streaming channel. You can continue to feed your channel with samples at the same time.

Warning: This example doesn't work if your module is configured as real-time. Please read Real-time configuration page for more informations.

Real-time configuration

Warning: Make sure to read and understand how to Create Luos modules before reading this page.

Message callbacks of modules can be really difficult to use when a project include high real-time constraints.
Luos provides different "real-time" configurations allowing you to choose the best way for you to deal with messages. The configuration of real-time is set during the initialization of a module.

Configurationexecution type
No real-time (default)runtime callback
Pollingno callback
Real-timeinterrupt callback

The following sections detail how the different configurations work.

No real-time configuration

This configuration is the default and most common setup. In this configuration, Luos calls the module callback during runtime (not interrupt). The time between the physical reception of a message and the callback may vary depending on the luos_loop() function call frequency.
With this configuration, you have no real constraints on the callback's time of execution, you can reply to a message directly on the callback.

To setup this configuration you have to simply setup the callback at module creation.

Here is a code example with a button:

void rx_btn_cb(module_t *module, msg_t *msg) {
    if (msg->header.cmd == ASK_PUB_CMD) {
        // The message is filled with global variable with proper data
        msg_t pub_msg;
        pub_msg.header.cmd = IO_STATE;
        pub_msg.header.target_mode = ID;
        pub_msg.header.target = msg->header.source;
        pub_msg.header.size = sizeof(char);
        pub_msg.data[0] = HAL_GPIO_ReadPin(BTN_GPIO_Port, BTN_Pin);
        // Sending the message
        luos_send(module, &pub_msg);
        return;
    }
}

void button_init(void) {
    // module creation: (callback, module type, Default alias)
    module_t* module = luos_module_create(rx_btn_cb, STATE_MOD, "button_mod");
}

void button_loop(void) {
}

Polling configuration

This configuration is often used into Arduino libraries to receive information in a basic way. This method allows to manage the messages only when the user wants to do it on the loop of the module.

To setup this configuration, you have to create your module without any callback.

See the following code as an example, with a button:

module_t* module;
void button_init(void) {
    module = luos_module_create(0, STATE_MOD, "button_mod");
}

void button_loop(void) {
    if (luos_message_available()) {
        msg_t *msg = luos_read(module);
        if (msg->header.cmd == ASK_PUB_CMD) {
            // The message is filled with global variable with proper data
            msg_t pub_msg;
            pub_msg.header.cmd = IO_STATE;
            pub_msg.header.target_mode = ID;
            pub_msg.header.target = msg->header.source;
            pub_msg.header.size = sizeof(char);
            pub_msg.data[0] = HAL_GPIO_ReadPin(BTN_GPIO_Port, BTN_Pin);
            // Sending the message
            luos_send(module, &pub_msg);
        }
    }
}

Real-time configuration

This method is adapted to high-frequency messages updates and requires an advanced understanding of embedded code and hardware capabilities. This configuration is not set by default.

In this configuration, module's callback is called in interruption. It means that if the execution time is too long into module's callback, it will block all the other interruptions and any other messages reception. The callback execution must be ended before any new message.

With this configuration you don't have time to send a reply back in the callaback. The response will then have to be deported into the main loop.

In order to use this configuration, you have to setup the callback at module creation and enable the real time mode.

Here is a code example with a button:

static module_t *module_pointer;
static volatile msg_t pub_msg;
static volatile int pub = LUOS_PROTOCOL_NB;

void rx_btn_cb(module_t *module, msg_t *msg) {
    // /!\ execution in interruption
    if (msg->header.cmd == ASK_PUB_CMD) {
        // The message is filled with global variable with proper data
        pub_msg.header.cmd = IO_STATE;
        pub_msg.header.target_mode = ID;
        pub_msg.header.target = msg->header.source;
        pub_msg.header.size = sizeof(char);
        pub_msg.data[0] = HAL_GPIO_ReadPin(BTN_GPIO_Port, BTN_Pin);
        // The request is saved to be executed into the regular program
        pub = ASK_PUB_CMD;
        module_pointer = module;
        return;
    }
}

void button_init(void) {
    //  module creation: (callback, module type, Default alias)
    module_t* module = luos_module_create(rx_btn_cb, STATE_MOD, "button_mod");

    // Hard real-time activation
    luos_module_enable_rt(module);
}

void button_loop(void) {
    if (pub != LUOS_PROTOCOL_NB) {
        // Sending the generated message into the callback
        luos_send(module_pointer, &pub_msg);
        pub = LUOS_PROTOCOL_NB;
    }
}

Code Examples

Here is a list of project example you can use to understand different concepts used in this documentation. You can use this table to find interesting project regarding specific features example you are looking for.

Projects Dynamic modules allocation Large data Streaming Object Dictionnary Routing table
Gate
Potentiometer
Gpio
Distance
Servo
Dxl
Load
Stepper
IMU
Button
LED
DC motor
Controlled motor
LED strip
Light sensor
Power switch

High level

This part of the Luos documentation is dedicated to people aiming to control or monitor a device trough a computer or a Raspberry Pi using classic programming ways such as Python, JavaScript, or Rust.

Luos provides a Python library, Pyluos. If you want to use another language, you should start reading about our JSON API.

JSON API

The JSON formated data is very common and widely used by many programming languages. Luos allows you to convert low-level Luos information into JSON objects, enabling conventional programming languages to easily interact with your device.
To do that, you must add a specific app module called Gate on your device.

The Gate module is an app that converts Luos messages from a device's network into JSON data format, and the other way from JSON to Luos messages.
The Gate module can be hosted into different kinds of nodesHardware element (MCU) hosting and running Luos and hosting one or several modules. allowing you to choose the communication way fitting with your project (USB, Wifi, Bluetooth, etc.)

Warning: The Gate module refreshes sensors information as fast as it can, so that can be intensive to Luos bandwidth.

How to start using the JSON API

Before using your device through JSON, you have to be connected to the communication flow depending on the node type hosting your Gate module.
Then you can start the Gate by sending:

{"detection": {}}\r

This command asks the Gate to start a topological detection, create a routing table, convert it into JSON and send it back to you.

Routing table messages

Warning: Make sure to read and understand how routing table works before reading this part.

After the Gate starts, the first message you receive is a routing table.
This first message is really important, because it contains all the information allowing you to create a code object for your device, containing all its features.

Routing table structure

A routing table in JSON consists in a list of the nodes present in the Luos network:

{
   "route_table":[
      {
         // node 1
      },
      {
         // node 2
      },
      {
         // node 3
      }
      // ...
   ]
}

Nodes information

Each listed node of the network has basic node information and a list of hosted modules:

{ // node 1
   "uuid":[1, 2, 3],
   "port_table":[1, 2],
   "modules":[
      {
         // module 1
      },
      {
         // module 2
      }
      // ...
   ]
}

Note: To understand the meanings of uuid and port_table, please refer to the routing table page.

Modules

Each listed module of a node has basics modules information:

{ // module 1
   "type":"Type",
   "id":1,
   "alias":"Alias"
}

Note: To understand the meanings of type, id and alias, please refer to the module page.

Full routing table example

{
   "route_table":[
      {
         "uuid":[2031684, 1112756496, 540423216],
         "port_table":[2, 65535],
         "modules":[
            {
               "type":"Gate",
               "id":1,
               "alias":"r_right_arm"
            }
         ]
      },
      {
         "uuid":[4915239, 1194612503, 540554032],
         "port_table":[4, 1],
         "modules":[
            {
               "type":"State",
               "id":2,
               "alias":"lock"
            },
            {
               "type":"Unknown",
               "id":3,
               "alias":"start_control"
            }
         ]
      },
      {
         "uuid":[2818086, 1194612503, 540554032],
         "port_table":[5, 3],
         "modules":[
            {
               "type":"Imu",
               "id":4,
               "alias":"gps"
            }
         ]
      },
      {
         "uuid":[2097186, 1194612503, 540554032],
         "port_table":[65535, 4],
         "modules":[
            {
               "type":"Color",
               "id":5,
               "alias":"alarm"
            },
            {
               "type":"Unknown",
               "id":6,
               "alias":"alarm_control"
            }
         ]
      }
   ]
}

Below is a visual representation of this routing table:

Module's information messages

When the JSON routing table is transmitted, the Gate starts to update and stream your network data with modules information.

This JSON is a "module" object listing all the modules by their alias and the values they send:

{
   "modules":{
      "module_alias1":{
         "value1":12.5
      },
      "module_alias2":{
         "value1":13.6,
         "value2":[1, 2, 3, 4]
      }
   }
}

You can use the exact same JSON object structure to send data to modules.

Here is the list of all values that can be used by modules:

Value nameDefinition
power_ratioPercentage of power of an actuator (-100% to 100%)
target_rot_positionActuator's target angular position (can be a number or an array)
limit_rot_positionActuator's limit angular position
limit_trans_positionActuator's limit angular position
limit_powerLimit ratio of an actuator's reduction
limit_currentLimit current value
target_rot_speedActuator's target rotation speed
target_trans_positionActuator's target linear position (can be a number or an array)
target_trans_speedActuator's target linear speed
timeTime value
compliantActuator's compliance status
pidSet of PID values (proportionnal, integral, derivative)
resolutionSensor's resolution value
offsetOffset value
reductionRatio of an actuator's reduction
dimensionDimension value
voltVoltage value
currentElectric current value
reinitReinitialisation command
controlControl command (play, pause, stop, rec)
colorColor value
io_stateIO state
ledBoard's LED
node_temperatureNode's temperature
node_voltageNode's voltage
uuidModule's uuid
renameRenaming an alias
revisionFirmware revision
trans_positionTranslation position value
trans_speedTranslation speed value
rot_positionRotation position value
rot_speedRotation speed value
luxLux (light intensity) value
temperatureTemperature value
forceForce value
momentTorque value
powerPower value
linear_accelLinear acceleration value
gravity_vectorGravity vector value
compassCompass value
gyroGyroscope value
accelAcceleration value
eulerEuler angle value
quaternionQuaternion values
rotational_matrixRotational matrix values
headingHeading
pedometerSteps number value
walk_timeWalk time value
luos_revisionluos's version
robus_revisionrobus's version

Here is an exemple of a message sent by a Potentiometer module about the rotation angle of the associated potentiometer:

{
   "modules":{
      "potentiometer_m":{
         "rot_position":12.5
      }
   }
}

Custom parameters and specific messages

Some messages are specifically handled:

Custom parameters can be defined and sent to modules through the JSON API, either with Python (Pyluos) or any other programming language on a computer side. Here is an example of a C function that can be implemented in order to send commands to modules in a Luos Network, through a gate:

def sendCmd(s, cmd, sleep_time=0.5):
    cmd = cmd + '\r'
    print(cmd)
    s.write(cmd.encode())
    time.sleep(sleep_time)
s = serial.Serial(sys.argv[1], 1000000)
# detect Luos network
sendCmd(s, '{"detection": {}}')
# set speed mode and compliant mode
sendCmd(s, '{"modules": {"controlled_moto": {"parameters": 2441}}}')
# set pid parameters
sendCmd(s, '{"modules": {"controlled_moto": { "pid": [20, 0.02, 90]}}}')
# set speed mode and non compliant mode
sendCmd(s, '{"modules": {"controlled_moto": {"parameters": 2440}}}')

Parameters are defined by a 16-bit bitfield.

ObjectDefinitionStructureModule(s)
parametersenabling or disabling some measurementLink to structure (GitHub)Stepper, Controlled-motor, Servo
parametersenabling or disabling some measurementLink to structure (GitHub)Imu

Other specific messages:

ObjectDefinitionModule(s)
registerMotor memory register filed with [register_number, value]Dynamixel, void
set_idA set id commandDynamixel, void
wheel_modeThe wheel mode parameter for Dynamixel servomotors True or FalseDynamixel, void
delayreduce modules refresh rateGate

Module exclusion messages

Module can be excluded of the network if a problem occurs (See message handling for more information). In this case, the Gate sends an exclusion message indicating that this module is no longer available:

{"dead_module": "module_alias"}

Sending large binary data

Binary data such as, for example, a motor tarjectory can't be included into a Json file if it is too large. In order to allow this type of transmission, the size of the binary data is sent through the Json, then followed by the actual data in binary format.

  • If the data is short, it can be displayed inside the JSON as a regular value (see the different values in Module's information messages section), or as a table of several values (for example a motor trajectory).

  • If the data is large, the defined value must be a table of one element, containing only the size of the binary data to be transfered, in bytes.

The following example shows a transfert of a binary data of 1024 bytes.

{
   "modules":{
      "module_alias1":{
         "rot_position":[1024]
      }
   }
}
###BINARY_DATA###

A Pyluos guide

Pyluos is the standard Python library to manage a Luos system with a computer. In this tutorial, you will learn how to install Pyluos in order to use Luos with Python on a computer, through a gate module.

Installation

Required: Installing Python and Pip

Warning: In order to use Pyluos library, Python and the Pip packet manager must be installed on your computer.

« Python is a programming language that lets you work more quickly and integrate your systems more effectively. » (Source)

« Pip is the standard package manager for Python. It allows you to install and manage additional packages that are not part of the Python standard library. » (Source)

If Python is not installed on you computer, download and run the last release according to your computer's OS: https://www.python.org/downloads/.

To install Pip, type the following commands in a console:

curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
python get-pip.py

Installing Jupyter Notebook

The tool Jupyter Notebook is needed for this tutorial. Jupyter Notebook will allow you to type Python commands in an internet browser to communicate with a Luos system, via Pyluos.

« The Jupyter Notebook App is a server-client application that allows editing and running notebook documents via a web browser. The Jupyter Notebook App can be executed on a local desktop requiring no internet access (...) or can be installed on a remote server and accessed through the internet. » (Source)

Type the following command in the console to install Jupyter:

pip install jupyter

Note: Feel free to consult Jupyter Notebook's.

Installing or updating Pyluos library

You are now ready to install Pyluos. The last Pyluos version is 1.2.0.

In a console, the following command will install the Pyluos library using the Pip packet manager:

pip install pyluos

If Pyluos is already installed, it may only need to be updated:

pip install --upgrade pyluos

Pyluos also provides auto generated pre-releases for advanced developers user. You can get it using:

pip install --pre pyluos

Start using Jupyter Notebook and Pyluos

Jupyter Notebook can be launched through a console:

jupyter notebook

In the browser page that opened, the New button creates a new Python file:

python

Note: In the previous picture, Jupyter use Python 3 but you also can use Python 2.7 depending on your computer configuration.

Jupyter

The Jupyter work-space looks like the following image. On the keyboard, Maj+Enter executes any selected part of code.

Now you are ready to code using Python.

Import Pyluos

The first thing to do is to call the Pyluos library along with the Device tool inside that library:

from pyluos import Device

This line is always used while programming behaviors and should be called before any connection with the device is made.

Device connection

Now you should be ready to use the Pyluos library and connect to your device. To do that you have to create a device object with your device address as argument.

Your device address could be an IP address (192.168.0.6 or my_device.local for example) or a serial port (COM13 on windows or /dev/cu.usbserial-DN2YEFLN on mac).

device = Device('address of the device')

This line makes the connexion between the computer and the device. Python should answer with this kind of message:

Connected to "address to the device".
Sending detection signal.
Waiting for first state...
Device setup.

Only once the connection is set it is possible to start programming behaviors.

Routing table display

Routing table can be easily displayed using Pyluos.

Pyluos can displays a list of all the modules by filtering the route table, and their associated characteristics (type, alias and ID). To display it, use the following command:

device.modules

Note: device is the name of the network.

Pyluos will give you a list of all modules without any topological informations :

-------------------------------------------------
Type                Alias               ID
-------------------------------------------------
Gate                gate                1
Voltage             analog_read_P1      2
Voltage             analog_read_P7      3
Voltage             analog_read_P8      4
Voltage             analog_read_P9      5
State               digit_read_P5       6
State               digit_read_P6       7
State               digit_write_P2      8
State               digit_write_P3      9
State               digit_write_P4      10
Angle               potentiometer_m     11

Pyluos also can interpreate route_table and transform it into a tree. This way we can display a lot more complete information usinig the following command :

device.nodes

Note: device is the name of the network.

Based on the previous example Pyluos will give you all informations about modules and topological informations :

 root : [4653093, 1194612501, 540554032]
        |  Type                Alias               ID
        └> Gate                gate                1
└── 1<=>0 : [4456498, 1347571976, 540555569]
            |  Type                Alias               ID
            └> Voltage             analog_read_P1      2
            └> Voltage             analog_read_P7      3
            └> Voltage             analog_read_P8      4
            └> Voltage             analog_read_P9      5
            └> State               digit_read_P5       6
            └> State               digit_read_P6       7
            └> State               digit_write_P2      8
            └> State               digit_write_P3      9
            └> State               digit_write_P4      10
    └── 1<=>0 : [4653107, 1347571976, 540555569]
                |  Type                Alias               ID
                └> Angle               potentiometer_m     11

In this example, 3 nodes (MCU) and their associated UUID are listed, along with their modules and associated characteristics (type, alias and ID). The characters after each set of node's modules and before the UUID's next node specify which connector is used. For example, 1<=>0 means the first node is connected from its second connector (1) to the first connector (0) of the next node.

Module type

Each module has a type (eg. Button, Led, ...). You can either retrieve your module's type from the previous code, or with the following line:

device.module_alias.type

module_alias being the alias you got from the previous listing.

Note: Unknown module types are defaulty set for custom module types such as some Luos apps.

Get and set modules informations

Once you have detected your modules, you can use these information like variables.

To access values you have to address them in the device object following this rules :

device.module_alias.variable

For example :

device.rgb_led_mod.color = [50,80,5] # Change the color of the LED in "rgb_led_mod" module

device.button_mod.state # Returns the status of the push button

device.button_mod.type # Returns the module type of the module "button_mod"

device.button_mod.luos_revision # Returns the version of luos

device.button_mod.robus_revision # Returns the version of robus

If you use ipython or Jupyter Notebook, you can use auto-completion using the Tab key to find every available objects and variables.

Auto-completion

Change a module name

The name of any module can be changed following this code. To list each module and its associated alias, refer to List available modules of your device section.

device.module_alias.rename("new_name")

For example:

device.rgb_led_mod.rename("myLED")

Note: You should restart your device and reconnect to it after this operation.

Note: To get back to the module default name, set a void name ("").

Full script

from pyluos import Device
device = Device('address of the device')

device.modules

device.rgb_led_mod.color = [50,80,5]
device.button_mod.state
device.button_mod.type

device.rgb_led_mod.rename("myLED")

Angle module type

The Angle module handles a rotation position value in degree.

Its type has access to all common capabilities.


Variables

Variable nameActionType
rot_positionReads the rotation position in degreeReads only: Float
ThresholdsThresholds position variation before filter_changed event triggers. Default value 10 °.Read / write: Float

Events

Event nameTrigger
changedAny movement on the position measurement
filter_changedMovement bigger than threshold

Color module type

The Color module handles an RGB color data.

Its type has access to all common capabilities.


Functions

Function name and parametersActionComment
control(self)Displays module type graphical interfaceOnly available using Jupyter notebook

Variables

Variable nameActionType
colorRGB colorread / write: [Char, Char, Char]
timeTransition time between color commandread / write: Float

Controlled-motor module type

This module type allows to control a motor with a reduction and a sensor (usually called motor-reducer or speed-reducer). This module computes PID for speed, position and motion planning.

You can find basic information about PID control here: An introduction to PID control with DC motor, and a code example to tune your PID at the end of this page.

Its type has access to all common capabilities.

Modules’s type settings:

Warning: This module doesn't save any of the following parameters, they must be set each time your module reboots.

Before using your controlled motor module, you have to setup the resolution, motor reduction and eventually the wheel size, if you plan to use translation modes. To check the configuration, just make a complete turn on the motor shaft with your hand and check if the rotation position value is OK.

Both PID’s values have to be set accordingly to the motor-reducer plugged to the board. Each different motor-reducer will have different PID’s values for position and speed control, and you have to define them by yourself. The default values [0, 0, 0] won’t have any effect on the motor, and must be changed if you plan to use any position or speed control mode. To setup your PID please refer to the example at the end of this page.

Warning: PID for position and speed must be set in your code as an initialization before starting to use your module with position or speed control.

Now that everything is configured, you can enable the control modes you want to use. You can use position and speed mode simultaneously. Power mode is only usable alone. The controlled motor is now ready to use, you can disable compliance to start moving the motor.


Functions

Function name and parametersActionComment
setToZero(self)Resets current position of the motor to 0You can use it to initialize the position of the motor
control(self)Displays module type graphical interfaceOnly available using Jupyter notebook

Variables

Motor settings

Variable nameActionType
positionPidSets position PID used for rotation position mode and translation position moderead / write: [float P, float I, float D]
speedPidSets speed PID used for rotation speed mode and translation speed moderead / write: [float P, float I, float D]
encoder_resDefines the motor sensor resolution, in steps by rotation.
This module considers that the sensor is placed before the reduction. If it is not your case, just setup a reduction ratio of 1.
read / write: float
reductionDefines the motor reduction.
Set this value to 1 if your sensor measures after the reduction.
read / write: float
wheel_sizeDefines wheel size used for translation mode, in mm.read / write: float

Motor control modes

Variable nameActionType
compliant- True: disables the motor driver, you can use it to move the motor by hand.
- False: Enables the motor driver.
read / write: Boolean (True or False)
power_modeEnables/Disables the power control mode.
Disables any other control mode if enabled.
read / write: Boolean (True or False)
rot_position_modeEnables/Disables the motor rotation position control mode.
Disables power mode and translation position mode if enabled.
Doesn't work if no position PID is configured.
read / write: Boolean (True or False)
rot_speed_modeEnables/Disables the motor rotation speed control mode.
Disables power mode and translation speed mode if enabled.
Doesn't work if no speed PID configured.
read / write: Boolean (True or False)
trans_position_modeEnables/Disables the motor translation position control mode.
Disables power mode and rotation position mode if enabled.
Doesn't work if no position PID configured.
read / write: Boolean (True or False)
trans_speed_modeEnables/Disables the motor translation speed control mode.
Disables power mode and rotation speed mode if enabled.
Doesn't work if no speed PID configured.
read / write: Boolean (True or False)

Motor sensing

Variable nameActionType
rot_positionReads rotation position in °
Reading it auto-Enables actualization.
read only: float
rot_positionStarts/Stops rotation position measurement actualizationwrite only: Boolean (True or False)
rot_speedReads rotation speed in °/s
Reading it auto-Enables actualization.
read only: float
rot_speedStarts/Stops rotation speed measurement actualizationwrite only: Boolean (True or False)
trans_positionReads translation position in mm
Reading it auto-Enables actualization.
read only: float
trans_positionStarts/Stops translation position measurement actualizationwrite only: Boolean (True or False)
trans_speedReads translation speed in mm/s
Reading it auto-enables actualization.
read only: float
trans_speedStarts/Stops translation speed measurement actualizationwrite only: Boolean (True or False)
currentReads the current consumption in A
Reading it auto-enables actualization.
read only: float
currentStarts/Stops current measurement actualizationwrite only: Boolean (True or False)

Motor commands

Variable nameActionType
power_ratioSets the power quantity send to the motor between -100% and 100%.read / write: float
target_rot_positionSets the target rotation position to reach in °.read / write: float
target_rot_speedSets the target rotation speed to reach in °/s.read / write: float
target_trans_positionSets the target translation position to reach in mm.read / write: float
target_trans_speedSets the target translation speed to reach in mm/s.read / write: float

PID Setting example code

The PID values allow your motor to stick to the target command as fast as possible. The quality of a set of PID values depends on time to reach the target position and position precision. Tuning a PID is something difficult and takes a lot of practice. It's really important to have simple ways to evaluate PID values impact on your motor before starting to tune these values. Here is the code we use at Luos to tune a PID by ourself. Use it with Jupyter notebook to get your plot instantly.

The main code:

%matplotlib inline
from pyluos import Device
from IPython.display import clear_output
import time
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt

# 1. Connect your Luos network (here using an USB module for example)
r = Device('/dev/cu.usbserial-DN2AAOVK')
r.modules

# 2. Select the module of your network you need to configure
module = r.controlled_moto

# 3. Setup module basic settings
module.encoder_res = 48
module.reduction = 26.851

def run_speed_test(velocity_target):
    module.rot_position = False
    module.rot_speed = True
    module.rot_position_mode = False
    module.rot_speed_mode = True
    module.target_rot_speed = 0.0
    module.compliant = False
    target = []
    real = []
    test_time_vector = []
    test_start_time = time.time()
    target.append(module.target_rot_speed)
    real.append(module.rot_speed)
    test_time = time.time()
    test_time_vector.append(0.0)
    while (test_time < test_start_time + 0.5):
        target.append(module.target_rot_speed)
        real.append(module.rot_speed)
        test_time_vector.append(test_time - test_start_time)
        test_time = time.time()
    module.target_rot_speed = velocity_target
    while (test_time < test_start_time + 2.5):
        target.append(module.target_rot_speed)
        real.append(module.rot_speed)
        test_time_vector.append(test_time - test_start_time)
        test_time = time.time()
    module.compliant = True
    plot_test(test_time_vector, target, real)

def run_pos_test(pos_target):
    module.rot_speed = False
    module.rot_position = True
    module.rot_speed_mode = False
    module.rot_position_mode = True
    module.target_rot_position = 0.0
    module.compliant = False
    target = []
    real = []
    test_time_vector = []
    test_start_time = time.time()
    target.append(module.target_rot_position)
    real.append(module.rot_position)
    test_time = time.time()
    test_time_vector.append(0.0)
    while (test_time < test_start_time + 1):
        target.append(module.target_rot_position)
        real.append(module.rot_position)
        test_time_vector.append(test_time - test_start_time)
        test_time = time.time()
    module.target_rot_position = pos_target
    while (test_time < test_start_time + 2.5):
        target.append(module.target_rot_position)
        real.append(module.rot_position)
        test_time_vector.append(test_time - test_start_time)
        test_time = time.time()
    module.compliant = True
    plot_test(test_time_vector, target, real)

def plot_test(test_time_vector, target, real):
    fig = plt.figure()
    ax = plt.subplot(111)
    ax.plot(test_time_vector,target,'r')
    ax.plot(test_time_vector,real,'b')
    plt.show()
    plt.close(fig)

Now, you are ready to tune the PID values for position and speed control modes. To do that, you have to try values to get best the result possible. In order to succeed, we advise you to do it step by step:

  1. Set P, I, and D values to 0.
  2. Increase the P value until you have a small oscillation around the target.
  3. Increase the D value until you have a fast and stable position.
  4. Increase with really small figures the I value to improve the motor precision.

The code you can use to tune your speed PID:

# Speed PID settings
module.speedPid = [0.1,0.1,0] # speed PID [P, I, D]
run_speed_test(100.0)

The code you can use to tune your position PID:

# Position PID settings
module.positionPid = [4.0,0.02,100] # position PID [P, I, D]
run_pos_test(100.0)

DC-motor module type

The DC-motor module allows to drive a DC motor using only power mode.

Its type has access to all common capabilities.


Functions

Function name and parametersActionComment
control(self)Displays module type graphical interfaceOnly available using Jupyter notebook

Variables

Variable nameActionType
power_ratioSets the power quantity send to the motor between -100% and 100%.read / write: float

Distance module type

The Distance module handles a sensor measuring a distance in mm.

Its type has access to all common capabilities.


Variables

Variable nameActionType
distanceReads the measured distance in mmread only: Float
thresholdThresholds distance variation before filter_changed event trigers. Default value 10 mm.read / write: Float

Events

Event nameTrigger
changedAny movement on the distance measurement
filter_changedMovement bigger than threshold

Dynamixel module type

The Dynamixel module allows to control Dynamixel motors.

Its type has access to all common capabilities.


Functions

Function name and parametersActionComment
set_id(self, id)Changes motor IDThis new Id will be saved by the Dynamixel motor. You have to detect motors again to make it work after this change.
detect(self)Launches a motor detectionYou have to run a luos detection to include or exclude new motors.
register(self, register, val)Sets a Dynamixel register value.This register only manage word size register. Use it only if you know what you do.
control(self)Displays module type graphical interfaceOnly available using Jupyter notebook

Variables

Variable nameActionType
compliant- True: disables the motor power, you can use it to move the motor by hand.
- False: Enables the motor power.
read / write: Boolean (True or False)
target_rot_positionSets the target rotation position to reach in °.read / write: Float
target_rot_speedSets the target rotation speed to reach in °/s.read / write: Float
wheel_modeEnables or disables wheel mode on motorread / write: Boolean (True or False)
rot_positionMeasured position of the motor in °.read / write: Float
temperatureMeasured temperature of the motor in °C.read / write: Float
positionPidSets position PID used for rotation position mode and translation position moderead / write: [float P, float I, float D]
power_ratio_limitMax power limit in %.read / write: Float
rot_position_limitMin and Max rotation position limit in °.read / write: [Float(min), Float(max)]

Gate module type

The Gate module allows to translate Json to Luos and Luos to Json constantly. This module continuously pulls data from the sensors detected on the network and streams it into a Json format. Also, it can receive Json data and convert it into a module command.

You need to have at least one of these modules in one of your nodes to use the Luos network with a computer using Pyluos or any other lib.

Json is a really mainstream standard allowing you to use your favorite language easily trough a Json library.

Its type has access to all common capabilities.


Functions

Function name and parametersActionComment
control(self)Displays module type graphical interfaceOnly available using Jupyter notebook

Variables

Variable nameActionType
delaySets or reads the network refresh delay in ms.read / write: Integer

Imu module type

The Imu module handles an inertial sensor.

Its type has access to all common capabilities.

Imu modules can measure:

  • Compass – Magnetic field data in micro-tesla on each axis
  • Gyro – X, Y, Z axis rotational acceleration data in degrees per second
  • Accel – X, Y, Z axis linear acceleration data in G
  • Heading – 360 degrees from North with Y+ axis as the pointer
  • Rotational Matrix – linear math 9 element matrix representation
  • Euler Angles – Pitch, roll, yaw based in degrees with frame reference
  • Quaternions – Sensor fused w, x, y, z rotational angles
  • Linear Acceleration – Linear acceleration in body frame coordinates
  • Gravity Vector – Which access gravity effects
  • Pedometer – Step number
  • walk time – Duration (second) of the walk

By default, the module will send only quaternions to keep a low number of data and avoid bus congestion. Retrieving any other types of measures requires to enable them first.

The easiest way to enable a measure is by using it, as pyluos automatically enables a called measure. For example, to retrieve the linear acceleration value when it’s disabled, you can execute:

device.Imu_mod.linear_acceleration

This command doesn’t allow you to disable the value after using it in order to keep your device responsive. Another way to enable or disable a value is to set it to True or False. For example, if you want to disable the linear acceleration measure previously activated, you can execute:

device.Imu_mod.linear_acceleration = False

Functions

Function name and parametersActionComment
control(self)Displays module type graphical interfaceOnly available using Jupyter notebook

Variables

Variable nameActionType
compassMagnetic field data in micro-tesla on each axisread only: [Float, Float, Float]
compassStarts/Stops compass measurement actualizationwrite only: Boolean (True or False)
gyroX, Y, Z axis rotational acceleration data in degrees per secondread only: [Float, Float, Float]
gyroStarts/Stops gyro measurement actualizationwrite only: Boolean (True or False)
accelerationX, Y, Z axis linear acceleration data in Gread only: [Float, Float, Float]
accelerationStarts/Stops acceleration measurement actualizationwrite only: Boolean (True or False)
heading360 degrees from North with Y+ axis as the pointerread only: [Float, Float, Float]
headingStarts/Stops heading measurement actualizationwrite only: Boolean (True or False)
rotational_matrixLinear math 9 element matrix representationread only: [Float, Float, Float, Float, Float, Float, Float, Float, Float]
rotational_matrixStarts/Stops rotational_matrix measurement actualizationwrite only: Boolean (True or False)
eulerPitch, roll, yaw based in degrees with frame referenceread only: [Float, Float, Float]
eulerStarts/Stops euler measurement actualizationwrite only: Boolean (True or False)
quaternionSensor fused w, x, y, z rotational anglesread only: [Float, Float, Float, Float]
quaternionStarts/Stops quaternion measurement actualizationwrite only: Boolean (True or False)
linear_accelerationLinear acceleration in body frame coordinatesread only: [Float, Float, Float]
linear_accelerationStarts/Stops linear_acceleration measurement actualizationwrite only: Boolean (True or False)
gravity_vectorWhich access gravity effectsread only: [Float, Float, Float]
gravity_vectorStarts/Stops gravity_vector measurement actualizationwrite only: Boolean (True or False)
pedometerStep numberread only: int
pedometerStarts/Stops pedometer measurement actualizationwrite only: Boolean (True or False)
walk_timeDuration (second) of the walkread only: Float
walk_timeStarts/Stops walk_time measurement actualizationwrite only: Boolean (True or False)

Example of use of your IMU module using Jupyter notebook

In this example, we will display in 3D the rotation sensor by using quaternions. In order to do that, we will use the pythreejs lib and jupyter notebook.

First, install and enable this library by typing these commands in a terminal:

pip install pythreejs

jupyter nbextension install --py --symlink --sys-prefix pythreejs

jupyter nbextension enable --py --sys-prefix pythreejs

Now, restart jupyter notebook and add this code to a new python script:

from pyluos import Device
import time
from pythreejs import *

# Create a cube to move following our sensor
cube = Mesh(
BoxBufferGeometry(3, 3, 3),
MeshPhysicalMaterial(color='green'),
position=[0, 0, 0],
castShadow = True
)

# Create a floor
plane = Mesh(
PlaneBufferGeometry(100, 100),
MeshPhysicalMaterial(color='gray'),
position=[0, -1.5, 0], receiveShadow = True)
plane.rotation = (-3.14/2, 0, 0, 'XYZ')

# Create a directional light following our cube
key_light = SpotLight(position=[0, 10, 10], angle = 0.3, penumbra = 0.1, target = cube, castShadow = True)
key_light.shadow.mapSize = (2048, 2048)

# Create a camera
c = PerspectiveCamera(position=[4, 12, 10], up=[0, 1, 0],
aspect=800/400)

# Create a scene
scene = Scene(children=[plane, cube, c, key_light, AmbientLight()])

# Display the scene with shadow and everything.
renderer = Renderer(camera=c,
scene=scene,
controls=[OrbitControls(controlling=c)],
width=800, height=400,
)
renderer.shadowMap.enabled = True
renderer.shadowMap.type = 'PCFSoftShadowMap'
display(renderer)

# Connect your Luos network (here using an USB module)
r = Device('/dev/cu.usbserial-DN38OIYT')

# Control the rotation of the cube with the rotation of the Imu sensor
while(True):
cube.quaternion = r.Imu_mod.quaternion
time.sleep(0.05)

You should obtain a result like this:

Light module type

The Light module handles a sensor measuring a light intensity in lux.

Its type has access to all common capabilities.


Variables

Variable nameActionType
luxReads the measured light intensity in luxread only: Float
thresholdThresholds light intensity variation before filter_changed event trigers. Default value 10 lux.read / write: Float

Events

Event nameTrigger
changedAny movement on the light intensity measurement
filter_changedMovement bigger than threshold

Servo module type

The Servo module allows to drive RC elements like servomotor

Its type has access to all common capabilities.


Functions

Function name and parametersActionComment
control(self)Displays module type graphical interfaceOnly available using Jupyter notebook

Variables

Variable nameActionType
rot_positionRotation position in °.read / write: float
max_angleSets max_angle value, in degrees (°) (180.0 by default)read / write: Float
min_pulseSets PWM minimum pulse value, in seconds (s) (0.0005 by default)read / write: Float
max_pulseSets PWM maximum pulse value, in seconds (s) (0.0015 by default)read / write: Float

State module type

The State module can handles a sensor (Button board for example), or an actuator (Power Switch board for example). Generally, this type of modules allows to manage bi-state elements such as on/off, pushed/release, 0/1, ...

Its type has access to all common capabilities.


Functions

Function name and parametersActionComment
control(self)Displays module type graphical interfaceOnly available using Jupyter notebook

Variables

Variable nameActionType
stateSets or reads the module stateread / write: Boolean (True or False)

Events

Event nameTrigger
changedAny state modification falling or raising
fallingState modification from True to False
raisingState modification from False to True

Stepper module type

This module type allows to control a stepper motor. It computes micro-stepping and motion planning.

Its type has access to all common capabilities.

Modules’s type settings:

Warning: This module doesn't save any of the following parameters, they must be set each time your module reboots.

The number of steps per turn must be defined, as well as the wheel diameter at the output of the motor if you wahnt to use translation. These specs may figure in your motor’s datasheet.


Functions

Function name and parametersActionComment
setToZero(self)Resets current position of the motor to 0You can use it to initialize the position of the motor
control(self)Displays module type graphical interfaceOnly available using Jupyter notebook

Variables

Motor settings

Variable nameActionType
stepPerTurnDefines the stepper resolutionread / write: float
wheel_sizeDefines wheel size used for translation moderead / write: float

Motor control modes

Variable nameActionType
compliant- True: disables the motor driver, you can use it to move the motor by hand.
- False: Enables the motor driver.
read / write: Boolean (True or False)
rot_position_modeEnables/Disables the motor rotation position control mode.
Disables power mode and translation position mode if enabled.
Doesn't work if no position PID is configured.
read / write: Boolean (True or False)
rot_speed_modeEnables/Disables the motor rotation speed control mode.
Disables power mode and translation speed mode if enabled.
Doesn't work if no speed PID configured.
read / write: Boolean (True or False)
trans_position_modeEnables/Disables the motor translation position control mode.
Disables power mode and rotation position mode if enabled.
Doesn't work if no position PID configured.
read / write: Boolean (True or False)
trans_speed_modeEnables/Disables the motor translation speed control mode.
Disables power mode and rotation speed mode if enabled.
Doesn't work if no speed PID configured.
read / write: Boolean (True or False)

Motor commands

Variable nameActionType
target_rot_positionSets the target rotation position to reach in °.read / write: float
target_rot_speedSets the target rotation speed to reach in °/s.read / write: float
target_trans_positionSets the target translation position to reach in mm.read / write: float
target_trans_speedSets the target translation speed to reach in mm/s.read / write: float

Voltage module type

The Voltage module handles a sensor measuring voltage.

Its type has access to all common capabilities.


Functions

Function name and parametersActionComment
control(self)Displays module type graphical interfaceOnly available using Jupyter notebook

Variables

Variable nameActionType
voltReads or writes voltage in Vread / write: Float
thresholdThresholds voltage variation before filter_changed event trigger. Default value 1.0 V.read / write: Float

Events

Event nameTrigger
changedAny state modification falling or raising
filter_changedVoltage variation bigger than threshold

Luos prototyping boards

Luos provides simple electronic boards examples to build in order to start prototyping using Luos modular technology. These examples are available on Github and contain the schematic and the Kicad file so that they can be easily reproduced to test Luos.

Start reading the board's general use page, then you can read the quick start page to start using your prototyping boards. You can consult the list of available Luos boards examples.

General guide to Luos electronic boards

Luos library has been designed to run on low-cost hardware. It works with all Arm microcontrollers, starting with the smallest and cheapest one: the Cortex-M0.

The prototyping boards are a set of small electronic boards examples, each one hosting Luos and providing with an electronic function (motor, distance sensor, battery, LED, potentiometer, etc.). These boards can be used to quickly develop an electronic device prototype in order to prove a concept without any knowledge in electronics: prototype boards are connected together with cables, behaviors can be programmed through a gate board on a computer, and the device can be tested in a matter of minutes!

Warning: All examples codes of this documentation use the pyluos Python library and are adapted to be used with Jupyter Notebook.

Boards general specifications

Almost every prototyping board in the provided examples is composed of a motherboard and a shield board. The motherboard, called L0, has a nodeHardware element (MCU) hosting and running Luos and hosting one or several modules. that hosts Luos. The shield board is added to a L0 to type it with an electronic function.

Note: Power category boards don't include L0 motherboard as they provide only with power functions and don't need communication. However. he communication data pass through their connectors to other communicating boards.

Here are the specifications of this motherboard:


  • Board name: L0
  • MCU: STM32f0
  • Dimensions: 20 x 26 mm
  • Supply Voltage: 5 V to 24 V
  • Output Voltage: 5 V
  • Connectors: 2x Robus connectors (DF11-8DP-2DS(24))
  • Sockets: 2x 6 connectors (826926-3)
  • Other Output: 1x micro-USB
  • USB Serial Speed: 1 Mbaud/s

Boards categories

Luos boards examples are organized in 6 categories. Each board belongs to at least one of these categories. Understanding every categories will help to understand how to connect the Luos boards together in order to achieve any type of electronic system.

Below is the list of the six categories:

SensorActuatorCommunication
Sensor boards are able to measure physical world environment.Actuation boards are able to act on the physical world.Communication boards (also called gates) are able to share your system’s inputs, outputs and configurations outside of your device, using a JSON API.
CognitionInterfacePower
Cognition are boards dedicated to execute your code or host your AI.These boards are built to interact with the user of the machine.Power boards are able to share their input power source into the RobusCore communication bus used by Luos to detect and communicate with modules in a network. wire to feed other boards.

Plugging boards together

Luos boards have at least 2 connection ports in their design. All connectors are the same, so that any board can be connected to another one using any of these ports. Just avoid to make a loop circuit, otherwise you will damage the communication between modules.

There is a correct side to plug a cable’s connector to a board. The small tab on the connector must face upward to plug correctly, as shown on the following pictures:

Wrong side imgRight side img
Wrong side, the upper surface is flatRight side, the tab is visible on the upper surface

Power management

Luos boards can share their power inputs through the network connection, allowing you to feed other boards. These boards belong to the power category. All the Luos boards can manage a voltage between 5V and 24V, up to 7A.

In a Luos network, you can have multiple power category boards. In this case, the power board with the highest voltage takes over and shares its power with other boards.

For example, for a device using a 12V motor and an USB board: The USB board belongs to the power category, so it can share its 5V into the network's wires. But you need 12V for your motor, so you will have to add a 12V AC plug board in your network to supply the motor. In this case, the USB board doesn’t share its power, only the AC plug board does, because 5V < 12V.

Some component needs specific voltage to work properly. For example, in order to use standard servomotor, you have to feed the Luos network with 5V or 7V. If you need to combine 7V and 12V motors in a system, for example, you can manage multiple voltages on the same network using a power isolator board.

External communication management

The boards from the Communication category allow you to easily control a Luos network. These boards host a module called "gate", they can communicate using different kinds of technologies and reach devices outside the device.
To start using Luos technology, you have to use at least one of these gates to be able to program your machine's behaviors.

The "gate" module's task is to stream the Luos network activity into a standard Json format file, and on the oposite to allow an external device to easily interact with any device in the network.

This way, it’s easy to use your favorite device and language to interact and control your device.

We created an open-source Python library managing this JSON API called Pyluos. Feel free to use it, copy it, and convert it into your favorite language. We are open to contribution for any programing languages. You can suggest any change or new API on the Luos' forum.

Get pyluos on github.

Update Luos, Robus and board's firmware

Follow this page's instruction to install Platform IO if it is not already the case.

To update Luos, RobusCore communication bus used by Luos to detect and communicate with modules in a network. or your modules' code, you must open the librairies tab on PlatformIO in Visual Studio Code:

To update the board's firmware you need to follow 3 steps:

1. Open the module folder that you want to update in Visual Studio Code

To do this, you must go to File -> Open the folder and go to the folder of the module you want.

2. Compile it to ensure there is no error

To compile your code, you must click on the Compile button at the bottom of your window:

If your terminal goes like this, it means that your download was successful:

If the compilation goes wrong in spite of your code having been perfectly compiled, do a cleaning by clicking on the ant button and choosing Clean in the list of project tasks:

3. Upload the new code into the board

To upload the new code into the board you must click on the Upload button :

If your terminal goes like this, it means that your download was successful:

If the compilation goes wrong, it may be because your driver is not updated specially on Windows. If this is the case, you need to install and run Zadig by following this tutorial on github.

Getting started

This page provides quick and easy tutorials to get started with Luos prototyping boards.

Tutorial #1

On the following steps, you will learn how to make a simple behavior with a RGB LED board and a Button board step-by-step.

What you will need

In the following example, we will make a LED turn on and off by pushing and releasing a button. You will need the following boards and accessories:

STEPS

1. Configure your computer

The default tool we use to control a Luos network is a board hosting a Gate module, with a Python lib called Pyluos.

To begin, you have to install Python and Pyluos library, following the pyluos documentation page.

2. Plug the boards together

Plug together all the boards with cables. You can plug them to any of the two connectors of each board, in any order.

Warning: Don't close a loop with the boards at each extremity.

Boards
From left to right: LED, Button, and USB . The plug order doesn’t matter.

3. Connect the device to a computer

Plug the USB board to a computer with micro-USB to USB cable.

In this particular example there is no high consumption component so we can use the power given by USB.

Your device is now powered and connected. All the low-level code and electronics is ready to use to help you program your own behaviors.

USB board

4. Interact with the device

The USB node handle a specific module called "Gate". There are other boards hosting "Gate" module and using different connection than USB. These particular modules convert Luos modules data into something easier to understand and manage, using JSON API.

Interacting with the Luos system and program behaviors will require to spot the USB connection on your computer. The following steps are explained on the General board use page with more details. In the following example, the associated port is COM13.

Once you know the port, you can connect using:

import pyluos
from pyluos import Device
device = Device('COM13')

When Pyluos establishes the connection with a Gate module, it asks to run a network detection. This detection allows to discover all boards wired together on the network.

To list the discovered boards you can run:

print(device.modules)

In this tutorial, Python should find three boards, the Gate (USB), the LED, and the Button boards. You can check that all are detected:

-------------------------------------------------
Type                Alias               ID
-------------------------------------------------
Gate                gate                1
Button              button_mod          2
Led                 rgb_led_mod         3

Knowing the alias of the boards, you can use them in your code. To read values from a sensor, you just have to read a variable. For example, you can see the button state using this code:

print(device.button_mod.pressed)

Python will answer True if you execute this line by pressing the button and False if you don't.

The same way, you can control a board by setting variables. In the following example we can control the led color using RGB values. Type and execute the following line:

device.rgb_led_mod.color = [50,80,5]

The LED turns on.

Changing to the value [0, 0, 0] will turn it off.

More details are provided on the page Luos boards general use.

5. Write a simple beahvior

You can now write a simple behavior that makes the LED to turn on when pushing the button and turn off when releasing it.

# Import libraries
from pyluos import Device
# Establish connection with the luos network
device = Device('COM13')

# Use an infinite loop to put the behavior inside
while 1:
    if (device.button_mod.pressed == True): # if the button is pushed
        device.rgb_led_mod.color = [0,15,15] # Assigns a color to the LED
    else: # If the button is released or idle
        device.rgb_led_mod.color = [0,0,0] # Turns the LED off

Test your behavior by executing the code.

LED board


Tutorial #2

The following video shows a basic tutorial explaining how to make a LED and a servomotor be responsive to a potentiometer.




What’s next?

These were simple tutorials to get you on tracks.

Now you just have to create awesome projects and share them with the community.

List of prototyping boards examples available on GitHub:

Battery power input board

Default Alias: N/A

Type: N/A

Number of module(s): 0

Image

Category(-ies)

Project source

Battery power input

How to use the Battery power input board

The Battery power input board allows to power your Luos Network using XT60 or JST battery interface. This board is not active, you can't detect it. The Battery power input board can provide 5V to 24V DC.

You can manage multiple voltage in the same network following Luos power rules defined in Luos boards general use or by using a power isolator board.

Button board

Default Alias: button_mod

Type: State

Number of module(s): 1

Image

Category(-ies)

Project source

Button

Button board functions

The Button board provides a push-button that can be used as an interface human-machine or as a end-of-course sensor, for example. It returns the state of the button (pushed or idle).

Power considerations

The Button board supports 5V to 24V DC.

Controlled-motor board

Default Alias: controlled_moto

Type: Controlled motor

Number of module(s): 1

Image

Category(-ies)

Project source

Controlled_motor

How to connect your motor-reducer to your boards

The Controlled-motor board is designed to control motors with a reducer and a sensor. It provides PH connector with 6 pins, where the motor can be plugged.

Connector's reference

Male connector Male connector's reference (on the board): B6B-PH-K-S(LF)(SN))

Female connector Female connector's reference (on the wire): PHR-6

Crimp Crimp's reference (on the wire): BPH-002T-P0.5S

Pinout and characteristics

Pinout
PHR-6 connector pinout.

This board accepts supply voltage from 7V to 24V.

To control regular DC motors (without reduction neither sensor), please refer to DC motor board’s documentation.

Warning: The USB board provides too weak power to drive a motor-reducer with this board. A power board such as Battery board or Power plug board shall be used.

This board is able to control DC motors with a reduction and a sensor (usually called motor-reducer or speed-reducer).

The Controlled-motor board provides a PID control on the output position, and PID control on the output speed, taking into account the reducer and the encoder.

You can find basic information about PID control here: An introduction to PID control with DC motor and a example code to tune your PID on the Controlled motor module page of this documentation.

DC-motor board

Default Alias: DC_motor1_mod, DC_motor2_mod

Type: DC-motor

Number of module(s): 2

Image

Category(-ies)

Project source

DC motor

DC-motor board functions

The DC-motor board allows to drive up to 2 low-power DC motors. This board is useful to easily drive a small and simple rover.

Power considerations

The DC-motor board supports 5V to 12V DC input to drive 5V to 12V DC motors up to 2 x 1.5 A (2 A peak).

Distance board

Default Alias: distance_mod

Type: Distance

Number of module(s): 1

Image

Category(-ies)

Project source

Distance

Distance board functions

The Distance board measures a distance using a time-of-flight laser range finder. This sensor is able to measure precise distances between 20 to 2000 mm.

Power considerations

The Distance board supports 5V to 24V DC input.

Dynamixel board

Default Alias: dxl_*id*

Type: N x Dynamixel motor

Number of module(s): N

Image

Category(-ies)

Project source

Dxl

Versions of Dynamixel board

There are two versions of this board. One is the version for XL320 Dynamixel, the other is for other types of Dynamixel (eg. AX12). Both boards have a different connector.

Dynamixel connectors

Except for this connection, both versions work exactly the same way.

How to connect and start the motors to the board

Dynamixel

The Dynamixel board is special because it has a dynamic number of visible modules, depending on the number of motors plugged to it. If you have 5 motors on your board, you will see 5 DynamixelMotor modules.

Note: If you don’t plug any motor to the board, it will create a special module called void_dxl.

This board creates modules dynamically upon motor detection. So in order to create modules, this board has to detect motors, and to detect them each motor needs to have a proper power supply.

Indeed, if you power the Luos network with an unadapted voltage, the motors won’t reply to the board requests and you won’t be able to see any Dynamixel module on your network.

To be detected, the Dynamixel motors need to use a baudrate of 1 000 000 baud and to have an ID between 1 and 30.

When your Dynamixel motors are properly configured, you can connect them to the Luos network. Be sure to respect the following order to have a proper start-up:

  1. Connect the board to the Luos network and to the Dynamixel motors.
  2. Connect the correct power supply to the luos network.
  3. Connect the USB board to your computer.
  4. Wait for the blue LED at the back of the board to turn off.

Note: The blue LED is ON when the network is busy detecting Dynamixel motors.

In order to begin using this board, you must disable the compliant mode, and you can then use the functions and variables of the Dynamixel module.

Warning: Dynamixel boards don’t belong to the power category. Thus, do not power your motors on the Robotis side, you won’t be able to share this power with others boards.

GPIO board

Default Alias: analog_read_P1, analog_read_P7, analog_read_P8, analog_read_P9, digit_read_P5, digit_read_P6, digit_write_P2, digit_write_P3, digit_write_P4

Types: State, Voltage

Number of module(s): 9

Image

Category(-ies)

Project source

Gpio

GPIO pinout and power consideration

The GPIO board allows you to use the pins of the L0 board through the Luos system. You can use Digital Write, Digital Read, or Analog Read pins.

GPIO pinout

This board creates a module for each available pin.

Power considerations

The GPIO board supports 5V to 24V DC input.

Warning: The pins only support 3.3V.

IMU board

Default Alias: Imu_mod

Type: Imu

Number of module(s): 1

Image

Category(-ies)

Project source

Imu

IMU board functions

The IMU board measures a wide set of position data and return values in several units. Refer to the IMU module page for more details.

Power considerations

The IMU board supports 5V to 24V DC.

Jack power input board

Default Alias: N/A

Type: N/A

Number of module(s): 0

Image

Category(-ies)

Project source

Jack power input

Jack power input board functions

The Jack power input board allows to power your Luos Network using a power Jack.

  • plug inner diameter : 2 mm
  • plug outer diameter : 5.5 mm

See the DC power jack datasheet for more information.

This board is not active, you can't detect it in a network.

You can manage multiple voltage in the same network following Luos power rules defined in Luos boards general use or by using a Power isolator board.

Power considerations

The Jack power input board can provide 5V to 24V DC.

Light board

Default Alias: light_sensor_mod

Type: Light

Number of module(s): 1

Image

Category(-ies)

Project source

Light sensor

Light board functions

The Light board measures human visible light intensity and returns a value in lux.

Power considerations

The Light board supports 5V to 24V DC input.

RGB LED strip board

Default Alias: led_strip_mod

Type: Color

Number of module(s): 1

Image

N/A

Category(-ies)

Project source

Led strip

Board function

This board controls a strip of several RGB LED. Refer to the Color module page for more details.

Power considerations

The RGB LED strip board supports 5V to 24V DC.

Potentiometer board

Default Alias: potentiometer_mod

Type: Angle

Number of module(s): 1

Image

Category(-ies)

Project source

Potentiometer

Potentiometer board functions

The Potentiometer board measures the board potentiometer's rotation in degree.

Power considerations

The board supports 5V to 24V DC input.

Power isolator board

Default Alias: N/A

Type: N/A

Number of module(s): 0

Image

Category(-ies)

Project source

Power isolator

Power isolator board

The Power isolator board allows to manage multiple voltages into the same Luos network. As this board is not active, you can't detect it in your network. This board isolates the voltage between each plugged-in side. You can use it to link components with different voltage needs. For example, to connect an XL320 motor (7V) and a MX28 motor (12V) on the same network, you can use a Dynamixel V2 board with a 7V power module for XL320, a Dynamixel V1 board with a 12V power module, and a Power isolator board to link both side together. You can connect a Gate like a USB board in the side you want without any functioning trouble.

Power isolator example image

Power Pi board

Default Alias: gate

Type: Gate

Number of module(s): 1

Image

Category(-ies)

Project source

Gate

Power Pi board

The Power Pi board links any Raspberry Pi-like board to a Luos network. This board allows you to convert the Luos network power into 5V and up to 2A in order to power your Raspberry Pi or Odroid without any other power source. This board hosts a Gate module allowing to your Raspberry Pi to control your entire Luos network using Pyluos or any other language as a single system image. The Power Pi board supports 5V to 24V DC input.

Connection of Power Pi board to a Raspberry Pi

The connection of the Power Pi board to an ODrive board or to a Raspberry Pi board is made according to the following images.

Warning: Be sure to plug the board on the right pins of the Raspberry Pi, and facing the right side. A bad connection may damage both boards.

Plug location
Red rectangles show where to plug the Power Pi board on an ODrive board (left) and on a Raspberry Pi board (right).

Preview
On the left, a Power Pi board connected to an ODrive board; on the right, a Power Pi board connected to a Raspberry Pi board.

How to easily start to create your code using this board

Coding on a Raspberry Pi in a device can be quite boring. Generally, you can't connect any screen and keyboard to work properly. That's why we created a small piece of code allowing to convert the Gate module stream into Web Socket messages. By using this Web Socket, you can connect pyluos or any other lib you created to your Raspberry Pi. This way you can create and execute your device's behaviors directly on your computer. When your behavior is complete and tested on your device, you just have to copy it into your Raspberry Pi to obtain an autonomous device.

To setup this pipe on your Raspberry Pi, please follow the tutorial on our forum.

How to setup your Power Pi's Gate

You need to setup the Power Pi board before to start using it.

First, you have to connect your Raspberry Pi to the Gate network.

Several solution exist to configure the Raspberry Pi’s Gate, we provide you with two of them according to your setup:

First solution: with a computer and the Raspberry Pi’s SD card

You will need the following parts:

  • A micro SD to SD card adapter
  • A computer with Bonjour installed on it You can download Bonjour by Apple here. Install it on your computer if you don’t already have it.

Plug the micro SD card to the micro-SD-to-SD adapter, and plug it to your computer. Ignore the messages that ask you if you want to format, and locate the SD card directory, named Boot. In Windows, it appears as a drive; in MacOS or Linux, go to

cd /Volumes/boot

Create a new file in this directory called wpa_supplicant.conf. The file should contain the following code:

country=fr
update_config=1
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev

network={
 scan_ssid=1
 ssid="SSID-Internet-box"
 psk="Secured-key"
}

Choose the country according to where you live, and replace SSID-Internet-box by the SSID of your internet device, and Secured-key by the password.

Save the file and eject the SD card. Replace it into the Raspberry Pi’s slot.

The Raspberry Pi can be located with the expression raspberrypi.local, thanks to the software Bonjour.

Second solution: with a screen and a keyboard

Raspberry-Pi connection

In order to establish a connection, you will need:

  • A QWERTY keyboard
  • An HDMI screen
  • An USB charger or USB to micro-USB cable to power up the Raspberry Pi
  • A micro USB to female USB adapter
  • A micro-HDMI to HDMI adapter
  • You can find the adapters you need in the Raspberry Pi zero toolkit, for example.

Plug all these elements and the Power Pi board on your Raspberry Pi (do not plug anything to the Power Pi board), and power it up. You should see on the screen the boot sequence and the file system expanding. After a few seconds, you should have a prompt asking you for username and password.

Usually, the Raspberry Pi has the default Raspberry username and password:

Username: pi
Password: raspberry

As you can see at the bottom of the boot screen, the SSH port is now open, so you should start by changing the password of your board to avoid any security issue.

To do that, use the following command:

sudo raspi-config

Choose option 1 to change your password and hostname, and choose option 2 to connect your board to your wifi.

You can check your Gate connection and retrieve the IP address using

ifconfig

and halt your system using

sudo halt

Your raspberry is now ready to be used, you can start setting your Luos network up.

Warning: The Power Pi board doesn’t belong to the Power category. Using the power input of your Raspberry Pi doesn’t allow you to supply the others boards in the Luos network. In order to make it work properly, please use a power board on your system.

How to use your Power Pi board

Power

Please note that the Power Pi board connected to the Raspberry Pi is already powered by the Luos network, through the power boards you use (Power board or Battery board).

However, the USB board can’t power the Raspberry Pi board, because several voltage transformations are applied along the network. You can also use an universal power supply (+5.1V micro USB) directly plugged to the Raspberry Pi.

Communication mode

By default, your Raspberry Pi starts a Luos service at boot called pyluos-usb2ws. This service creates a pipe between a websocket opened on port 9342, and the Luos system. If you send standard Luos Json data into this web socket, it is directly sent into the Luos network.

This way, you can control your device from your computer even if it is moving or dispatched. For example, if you are using pyluos to control your device, you can start your program with:

from pyluos import Device
device = Device("raspberrypi.local")
device.modules

In this example, you can replace raspberrypi.local by your Raspberry Pi’s IP or hostname.

You should see the list of modules connected to the Power Pi board.

Cognition mode

Also, you can use your Raspberry Pi like an embedded computer for your device.

To send your Json data to your network, please use the serial port /dev/ttyAMA0 of your Raspberry Pi, as you can do it with the USB board.

Power-switch board

Default Alias: switch_mod

Type: State

Number of module(s): 1

Image

Category(-ies)

Project source

Power switch

Board function

The Power-switch board allows you to interrupt another circuit up to 10A on 230V AC or 30V DC. The blue LED on the module indicates when the link between 2 entries on the screw connector is closed.

Power considerations

The Power-switch board supports 5V to 24V DC input.

RGB LED board

Default Alias: rgb_led_mod

Type: Color

Number of module(s): 1

Image

Category(-ies)

Project source

Led

Board function

This board contains an RGB LED that can be controlled to make a light of any chosen color. Refer to the Color module page for more details.

Power considerations

The RGB LED board supports 5V to 24V DC.

Servo board

Default Alias: servo1_mod, servo2_mod, servo3_mod, servo4_mod

Type: Servo

Number of module(s): 4

Image

Category(-ies)

Project source

Servo

How to connect your servo-motors to your modules

The Servo board has 4 servo-motor ports ordered as shown on the following picture, from S1 to S4.

Servomotor ports

Power considerations

The Servo board accepts supply voltage from 5V to 7V. Watch out to always power your motor with an appropriate voltage.

Warning: A USB board generally provides too weak power to drive a servomotor properly. It must be plugged to a Power plug board, for example.

Stepper board

Default Alias: stepper_mod

Type: Stepper

Number of module(s): 1

Image

Category(-ies)

Project source

Stepper

How to connect a stepper motor to the Stepper board

The Stepper board has one 4-pin PH connector where a stepper motor can be plugged.

Power considerations

This board accepts supply voltage from 7V to 24V.

Warning: USB board provides too weak power to drive a motor-reducer with the Stepper board. A power board such as Battery board or Power plug board shall be used.

USB board

Default Alias: gate

Type: Gate

Number of module(s): 1

Image

Category(-ies)

Project source

Gate

Driver installation

With Windows, you must install VCP and D2XX drivers first. They are available for download on these pages:

https://www.ftdichip.com/Drivers/VCP.htm

https://www.ftdichip.com/Drivers/D2XX.htm

Select the files to download according to your system (x86 or x64) and install them on your computer.

How to connect the USB board to your computer

There are 2 micro-USB ports, but one of them is only used to manually update the board. The other one is the one we will use in this page.

The right USB port used on this page is the one at the opposite of the 2 Luos connectors.

USB board

How to use the USB board

Luos' USB board acts like a serial port on your system. To control your device, you have to get and set Json data into the serial port opened by the USB board. In order do that with pyluos, you can use the following python code:

from pyluos import Device
device = Device('COM13')
device.modules

On Windows

On Windows, a COM port is usually used (like COM1, COM2, COM3, etc.). It can be found in Device Manager (right-click on Start button), after it’s plugged:

Port COM

Once the port is known, the connexion can be set on pyluos with python:

device = Device('COM27')

On MacOS

To list the available serial ports, use the following command line:

ls /dev/cu.usbserial-*

Once the port is known, the connexion can be set on pyluos with python:

device = Device('/dev/cu.usbserial-DN30VKKB')

On Linux

To list the available serial ports, type the following in a terminal:

dmesg | grep tty

Once the port is known, the connexion can be set on pyluos with python:

device = Device('/dev/ttyS0')

Serial connectivity with other languages

In order to communicate from a computer to a Luos network through a gate, a serial connection can be established. This serial connectivity must have the following parameters:

  • Baudrate: 1,000,000 Bits/s
  • 8 Bits per transfer
  • 1 stop bit
  • No parity bit
  • Least significant bit sent first
  • Non inverted

Although the connection can be made with Pyluos, the Python library, other languages can be used on the computer side. Here is a C Linux serial connection example:

void init_luos_comm(luos_t* m)
{
 m->serial_fd = open(SERIAL_PORT, O_RDWR);

 // Check for errors
 if (m->serial_fd < 0)
 {
     printf("Error %i from open: %s\n", errno, strerror(errno));
     return -1;
 }

 struct termios tty;
 memset(&tty, 0, sizeof tty);

 if (tcgetattr(m->serial_fd, &tty) != 0)
 {
     printf("Error %i from tcgetattr: %s\n", errno, strerror(errno));
     return -1;
 }

 tty.c_cflag &= ~PARENB;        // Disable parity
 tty.c_cflag &= ~CSTOPB;        // Clear stop field
 tty.c_cflag |= CS8;            // 8 bits per byte
 tty.c_cflag &= ~CRTSCTS;       // Disable RTS/CTS hardware flow control
 tty.c_cflag |= CREAD | CLOCAL; // Turn on READ & ignore ctrl lines (CLOCAL = 1)
 tty.c_lflag &= ~ICANON;        // Disable canonical mode
 tty.c_lflag &= ~ECHO;          // Disable echo
 tty.c_lflag &= ~ECHOE;         // Disable erasure
 tty.c_lflag &= ~ECHONL;        // Disable new-line echo
 tty.c_lflag &= ~ISIG;          // Disable interpretation of INTR, QUIT and SUSP

 // Turn off s/w flow ctrl
 tty.c_iflag &= ~(IXON | IXOFF | IXANY);

 // Disable any special handling of received bytes
 tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL);

 // Prevent special interpretation of output bytes (e.g. newline chars)
 tty.c_oflag &= ~OPOST;

 // Prevent conversion of newline to carriage return/line feed
 tty.c_oflag &= ~ONLCR;

 // Wait for up to 1s (10 deciseconds), returning as soon as any data is received.
 tty.c_cc[VTIME] = 10;
 tty.c_cc[VMIN] = 0;

 // Set in/out baud rate to be 1000000
 cfsetispeed(&tty, B1000000);
 cfsetospeed(&tty, B1000000);

 // Save tty settings
 if (tcsetattr(m->serial_fd, TCSANOW, &tty) != 0)
 {
     printf("Error %i from tcsetattr: %s\n", errno, strerror(errno));
     return -1;
 }
 fcntl(m->serial_fd, F_SETFL, FNDELAY);
 usleep(500000);
}

USB board power delivery

The USB board power-delivery in the Luos network is limited to 500 mA. This board can’t power too many boards and power-demanding ones like, for example, a DC-motor board with one or two motors connected. If you experiment power issues, feel free to add a power category board like a Jack power input board.

Wifi-BLE board

Default Alias: gate

Type: Gate

Number of module(s): 1

Image

N/A

Category(-ies)

Project source

Gate

How to configure the Wi-Fi network

This board allows to enable Wi-Fi communication into a Luos network.

  1. Plug the board to a powered Luos network or to a power source. It automatically turns the Wi-Fi on.
  2. Connect your computer to the board's Wi-Fi. A page automatically opens in your default browser.
  3. On the page, choose the name of the Wi-Fi network or choose an existing network to connect to.

Power considerations

This board accepts supply voltage from 7V to 24V.

Wire power input board

Default Alias: N/A

Type: N/A

Number of module(s): 0

Image

Category(ies)

Project source

Wire power input

How to use the Wire power input board

The Wire power input board allows to power your Luos Network using a wire-screw interface. As this board is not active, you can't detect it into a network.

Power considerations

The Wire power input board can provide 5V to 24V DC.

You can manage multiple voltage in the same network following Luos power rules defined in Luos boards general use or by using a Power isolator board.

Cables

Default Alias: N/A

Type: N/A

Number of module(s): N/A

Image

Category(-ies)

N/A

Project source

Cables

How do the cables work?

The cables are used to link the Luos bords together. There are two lengths of cables : 10 cm (3.9 in) cables and 20 cm (7.9 in) cables. However, it is possible to build a cable from any disired length (see the next section).

Maximal current value: The Luos cable can handle up to 7 A.

Boards connection: The connectors on the board side and on the cable side have a foolproof so that they can plug together in one way only. Fore more information about plugging boards together with cables, please follow this link.

How to buid a Luos compatible-cable?

If you need a cable with a length not available, you can build one, provided you have electrical wire and two connectors:

  • Electrical wire: AWG 22
  • Connectors: DF11-8DS-2C, 2mm

The datasheet connector is available here.

The board connector associated to the cables is DF11-8DP-2DS. this connector's pinout on Luos' boards is shown in the following picture:

Luos board connector pinout

The routing of the board connector is as shown below:

Luos board connector routing

Luos board connector routing
Click on the image to display it in full size.

On a Luos cable, the wires are organized in this order:

  • Pin 1 (first connector end) on pin 1 (second connector end)
  • Pin 2 (first connector end) on pin 2 (second connector end)
  • Pin 3 (first connector end) on pin 3 (second connector end)
  • ...
  • Pin 8 (first connector end) on pin 8 (second connector end)

Note: If you wish to use only 4 wires instead of 8 (data only, no power), this is possible with using the pins 4 (B_RS_485_P), 5 (A_RS_485_N), 3 or 6 (PTP), and GND.


Follow Watch Star

Luos is constantly evolving! Keep in touch to follow the last updates: