Zastosowanie JavaScript w Robotyce
Marcin Borkowski | LinkedIn
We talk about JavaScript. Each month in Warsaw, Poland.

Cylon.js to obecnie najszybciej rozwijający się i najlepiej udokumentowany framework JavaScript do komunikacji z urządzeniami typu „Open Hardware“.

Tak jest! Cylon.js to naprawdę najszybciej rozwijający się framework tego typu. Jeśli nie obsługuje jeszcze któregoś z popularnych urządzeń open-hardware, z całą pewnością za chwilę będzie.
- tempo rozwojuW Marcu 2014 Cylon.js obsługiwał 6 platform.
Niemal 10 m-cy później Cylon.js potrafi obsłużyć w sumie aż 33 platformy (wzrost o 550%)!
Niektóre z nich to: Arduino, ARDrone, Leap Motion, Spark, Sphero, Neurosky, Pebble, Raspberry Pi, Philips Hue, Bluetooth SMART
- ArchitekturaZanim napiszemy pierwszy kod, kilka słów o architekturze. Pozwoli nam to lepiej zrozumieć, czym jest i jak działa Cylon.js
- ArchitekturaMCP (Master Control Program) - jest odpowiedzialny za zarządzanie cyklem życia programu, jak definiowanie „robotów“, zatrzymywanie/wznawianie ich pracy, obsługa API.
- ArchitekturaREST API - Cylon.js oferuje wbudowany interfejs RESTful API, który możemy wykorzystać do obsługi wszelkich zdarzeń związanych zarówno z samym programem, jak i zdefiniowanymi robotami. Wywołania API kierowane są bezpośrednio do MCP.
- ArchitekturaRobots - Robotami w ujęciu Cylon.js nazywamy zbiór (1 lub więcej) urządzeń (devices) oraz połączeń (connections), zdolnych do wzajemnej komunikacji. Definiowanie robotów odbywa się na poziomie MCP.
- ArchitekturaConnections - definicja połączeń dla wykorzystywanych urządzeń, np. określenie portu USB, do którego podłączono dane urządzenie.
Devices - definicja urządzeń, nad którymi chcemy mieć kontrolę. W przypadku np. Arduino, urządzeniami będą wszystkie elementy zewnętrzne, które do niego podłączono, np. dioda led, czujnik temperatury, servo itp.
- ArchitekturaDrivers, Adaptors - zapewniają komunikację z urządzeniami i poszczególnymi usługami. Adapterem jest np. cylon-firmata, który instalujemy jako submoduł do komunikacji z Arduino. Sterownikiem (driver) jest za to część programu służąca do obsługi komunikacji z danym urządzeniem (device).
- Architektura
- rozpoczynamy prace
$ npm install cylon
Instalowany jest core frameworku wraz z pakietami cylon-gpio i cylon-i2c. Praca z poszczególnymi platformami wymaga doinstalowania właściwych dla tych platform pakietów, dostępnych w ramach frameworka.
- rozmówki z Arduino
$ npm install cylon-firmata
- rozmówki z Arduino
$ npm -ls --depth 0
co daje przykładowy wynik:
- rozmówki z ArduinoStandardowo, aby Arduino mogło wykonywać dla nas określone czynności, niezbędne jest zuploadowanie do jego niewielkiej pamięci (wersja UNO mieści ~32 kb kodu) wcześniej przygotowanego kodu.
Takie rozwiązanie, poza oczywistymi plusami (wszystko w jednym - brak konieczności podlączania dodatkowego komputera) posiada również pewne wady, mogące uprzykrzyć nasze pierwsze kroki z robotyką...
- rozmówki z Arduino
- rozmówki z ArduinoCylon.js swoją komunikację z Arduino opiera na protokole Firmata. Dzięki temu:
JavaScript ;-), Processingiem, Pythonem, Perlem, Rubym, Clojure, Javą, .NET, Flashem / AS3, PHP, iOS)
- rozmówki z ArduinoAby nasze programy napisane z użyciem Cylon.js były poprawnie interpretowane przez Arduino, niezbędne jest wgranie do jego pamięci sketcha protokołu Firmata (jest to jednorazowa operacja wykonywana na danym urządzeniu).
Szczegółowy opis jak tego dokonać znajduje się tutaj oraz (aktualizacja) tutaj.
- sterowanie diodą LED
- sterowanie diodą LEDCylon:
var Cylon = require('cylon');
Definiujemy robota:
Cylon.robot({
- sterowanie diodą LED
connections: {
arduino: { adaptor: 'firmata', port: '/dev/ttyACM0' }
},
- sterowanie diodą LED
devices: {
led: { driver: 'led', pin: 13 }
},
- sterowanie diodą LED
work: function(my) {
every((1).second(), my.led.toggle);
}
Uruchamiamy naszego robota:
}).start();
- sterowanie diodą LED
var Cylon = require('cylon');
Cylon.robot({
connections: {
arduino: { adaptor: 'firmata', port: '/dev/ttyACM0' }
},
devices: {
led: { driver: 'led', pin: 13 }
},
work: function(my) {
every((1).second(), my.led.toggle);
}
}).start();
- sterowanie diodą LED
$ node led_blink.js
gdzie led_blink.js to nazwa pliku, w której zapisaliśmy nasz program.
UWAGA: Wyłączając powyższy program, automatycznie zatrzymujemy wszelkie dotychczas wykonywane przez Arduino zaprogramowane czynności.
- Udostępniamy proste APIZ wcześniejszych slajdów dowiedziałeś się, że Cylon.js udostępnia możliwość definiowania własnych metod API.
W kolejnym przykładzie zróbmy to samo, jednak z tą różnicą, że dioda LED nie będzie zapalana w interwale a poprzez wywołanie odpowiedniej metody z API.
- Udostępniamy proste APICylon:
var Cylon = require('cylon');
- Udostępniamy proste API
Cylon.api({
host: '0.0.0.0',
port: 8080,
ssl: false
});
- Udostępniamy proste API
Cylon.robot({
/* Tym razem dla porządku nadamy mu imię */
name: 'ledMonster',
connections: {
arduino: { adaptor: 'firmata', port: '/dev/ttyACM0' }
},
devices: {
led: { driver: 'led', pin: 13 }
},
- Udostępniamy proste API
/* Definiujemy tym razem puste zadanie */
work: function() {},
/* Tworzymy własną funkcję, której każde wywołanie
będzie przełączać aktualny stan diody LED (on/off) */
ledToggle: function() {
console.log('Led Toggle');
this.led.toggle();
}}).start();
- Udostępniamy proste APIPo uruchomieniu programu diody LED, które w poprzednim przykładzie zapalały się i gasiły w interwale, teraz pozostają wygaszone.
Jednak w tym przykładzie zdefiniowaliśmy interfejs API, dostępny z lokalnej przeglądarki pod adresem http://localhost:8080/.
- Udostępniamy proste APIWejście do API nie wymaga żadnego logowania, choć Cylon.js umożliwia zaimplementowanie prostego mechanizmu autoryzacji.
W dashboardzie znajdziemy listę zdefiniowanych przez nas robotów:
- Udostępniamy proste APIPo wybraniu naszego robota (LEDMonster) otrzymujemy dostęp do listy poleceń, które za pomocą API możemy wykonać. Znajdują się tu wszystkie funkcje umieszczone w Robocie jako niestandardowe (czyli np. nasz ledToggle).
Kliknięcie przycisku [RUN] spowoduje natychmiastowe wywołanie zdefiniowanej przez nas funkcji, czego rezultatem będzie zmiana aktualnego stanu diody LED (on/off).
- Podłączamy Leap MotionWe wcześniejszych przykładach wykorzystywaliśmy Arduino z wpiętym do niego urządzeniem peryferyjnym - diodą LED.
W tym przykładzie będziemy zapalać i gasić ją za pomocą prostych gestów. Aby było to możliwe, wykorzystamy Leap Motion - kontroler ruchu znajdujący się na liście obsługiwanych przez Cylon.js urządzeń.
- Podłączamy Leap Motion
var Cylon = require('cylon');
var state = {
lightOn: false
};
Cylon.robot({
name: 'LEDMonster',
connections: {
arduino: { adaptor: 'firmata', port: '/dev/ttyACM0' },
leapmotion: { adaptor: 'leapmotion' }
},
devices: {
led: { driver: 'led', pin: 11, connection: 'arduino' },
leapmotion: { driver: 'leapmotion', connection: 'leapmotion' }
},
- Podłączamy Leap Motion
work: function(my) {
this.leapmotion.on('hand', function(hand) {
if(hand.type === 'left' && state.lightOn) {
console.log('Light OFF');
my.led.turnOff();
state.lightOn = false;
} else if(hand.type === 'right' && !state.lightOn) {
console.log('Light ON');
my.led.turnOn();
state.lightOn = true;
} else {}
});
...
- Podłączamy Leap Motion
...
/* Zapalaj/Wygaszaj diodę w interwale = 250ms JEŚLI state.lightOn */
every(250, function() {
if(state.lightOn) {
my.led.toggle();
} else {
my.led.turnOff();
}
});
}
}).start();
Chętnie na nie teraz odpowiem :)
Możesz zadać je również po tej prezentacji (zapraszam w kuluary).
Pozostałe formy kontaktu:
marcin@makerlab.pl | LinkedIn | GoldenLine