The JavaScript Evolution Of Open Source Robotics – cylonjs.com – Arduino



The JavaScript Evolution Of Open Source Robotics – cylonjs.com – Arduino

0 0


cylon-preso-scotlandjs-2014


On Github hybridgroup / cylon-preso-scotlandjs-2014

The JavaScript Evolution Of Open Source Robotics

cylonjs.com

Good Afternoon

This is @ScotlandJS

I am @deadprogram

Ringleader

@hybrid_group

The other guy is @adzankich

Serious Programming Guy

@hybrid_group

hybridgroup.com

kidsruby.com

JavaScript Robotics

The future is already here, it's just not very evenly distributed William Gibson

A JavaScript Framework for Robotics & Physical Computing

Multiple Hardware Devices

Different Hardware Devices

At the Same Time!

Cylon.js Architecture

Cylon.js API

Test-Driven Robotics

Command Line Interface

gort.io

RobotOps - DevOps For Robots

robotops.com

Show Me The Demo!

Arduino

var Cylon = require('cylon');

Cylon.robot({
  connection: { 
    name: 'arduino', 
    adaptor: 'firmata', 
    port: '/dev/ttyACM0' 
  },
  device: {
    name: 'led', 
    driver: 'led', 
    pin: 13
  },
  work: function(my) {
    every((1).second(), my.led.toggle);
  }
}).start();

Tessel

var Cylon = require('cylon');

Cylon.robot({
  connection: { 
    name: 'tessel', 
    adaptor: 'tessel', 
    port: 'LED'
  },
  device: {
    name: 'led', 
    driver: 'led', 
    pin: 2
  },
  work: function(my) {
    every((1).second(), my.led.toggle);
  }
}).start();

Choose Your Own Hardware Adventure!

To win an Arduino, tweet

@arduino and @cylonjs

To win a Pebble, tweet

@pebble and @cylonjs

Sphero + Pebble + Robeaux

Conway's Game Of Life

Conway's Game Of Life... With ROBOTS!

var Cylon = require('cylon');

var bots = [
  { port: '/dev/rfcomm0', name: 'Thelma' },
  { port: '/dev/rfcomm1', name: 'Louise' },
  { port: '/dev/rfcomm2', name: 'Grace' },
  { port: '/dev/rfcomm3', name: 'Ada' },
  { port: '/dev/rfcomm4', name: 'Mary' }
];

var Green = 0x00FF00;
var Red = 0xFF0000;

var ConwayRobot = (function() {
  function ConwayRobot() {}

  ConwayRobot.prototype.connection = { name: 'Sphero', adaptor: 'sphero' };
  ConwayRobot.prototype.device = { name: 'sphero', driver: 'sphero' };

  ConwayRobot.prototype.born = function() {
    this.contacts = 0;
    this.age = 0;
    this.alive = true;
    this.life();
    this.move();
  };

  ConwayRobot.prototype.move = function() {
    this.sphero.roll(60, Math.floor(Math.random() * 360));
  };

  ConwayRobot.prototype.life = function() {
    this.alive = true;
    this.sphero.setRGB(Green);
  };

  ConwayRobot.prototype.death = function() {
    this.alive = false;
    this.sphero.setRGB(Red);
    this.sphero.stop();
  };

  ConwayRobot.prototype.enoughContacts = function() {
    return (this.contacts > 2 && this.contacts < 7);
  };

  ConwayRobot.prototype.birthday = function() {
    this.age += 1;

    console.log("Happy birthday, " + this.name + ". You are " + this.age + " and had " + this.contacts + " contacts.");

    if (this.enoughContacts()) {
      if (this.alive == false) { this.rebirth(); }
    } else {
      this.death();
    }

    this.contacts = 0;
  };

  ConwayRobot.prototype.work = function(me) {
    var self = this;
    me.sphero.on('connect', function() {
        me.sphero.detectCollisions();
        me.born();
    });

    me.sphero.on('collision', function() {
      self.contacts += 1;
    });

    every((3).seconds(), function() {
      if (me.alive != false) { me.move(); }
    });

    every((10).seconds(), function() {
      if (me.alive != false) { 
        me.birthday(); 
      }
    });
  };

  return ConwayRobot;

})();

for (var i = 0; i < bots.length; i++) {
  var bot = bots[i];
  var robot = new ConwayRobot;

  robot.connection.port = bot.port;
  robot.name = bot.name;

  Cylon.robot(robot);
}


var PebbleRobot = (function() {
  function PebbleRobot() {}

  PebbleRobot.prototype.connection = { name: 'pebble', adaptor: 'pebble' };
  PebbleRobot.prototype.device = { name: 'pebble', driver: 'pebble' };
  PebbleRobot.prototype.work = function(me) {
      var dead = 0;
      var alive = 0;
      me.pebble.on('connect', function() { console.log("Pebble Connected!"); });
      every((1).second(), function(){
        alive = 0;
        dead = 0;
        for (var i = 0; i < bots.length; i++) {
          var bot = bots[i];
          me.master.findRobot(bot.name, function(error, spheroBot) {
            if (spheroBot.alive == true) {
              alive += 1; 
            } else {
              dead += 1;
            }
          });    
        }
        var msg = "alive: " + alive + "\ndead: " + dead + "\n" 
        me.pebble.message_queue().push(msg);
      });
  };

  return PebbleRobot;
})();

var robot = new PebbleRobot;
robot.name = "pebble";
Cylon.robot(robot);

Cylon.api({host: '192.168.1.116', port: '8080', ssl:  false});

Cylon.start();

Robeaux - Universal Robot API

ARDrone + OpenCV

var Cylon = require('cylon');
var haarcascade = "" + __dirname + "/haarcascade_frontalface_alt.xml";

Cylon.robot({
  connections: [
    { name: 'opencv', adaptor: 'opencv' }, 
    { name: 'ardrone', adaptor: 'ardrone', port: '192.168.1.1' }
  ],
  devices: [
    { name: 'drone', driver: 'ardrone', connection: 'ardrone' }, 
    { name: 'window', driver: 'window', conneciton: 'opencv' }, 
    { name: 'mat', driver: 'mat', conneciton: 'opencv' }
  ],
  work: function(my) {
    var self = this;
    self.detect = false;
    self.image = null;
    my.drone.getPngStream().on('data', function(png) {
      my.mat.readImage(png, function(err, img) {
        self.image = img;
        if (self.detect === false) {
          my.window.show(img);
        }
      });
    });
    my.mat.on('facesDetected', function(err, im, faces) {
      var biggest, center_x, f, face, turn, _i, _len;
      biggest = 0;
      face = null;
      for (_i = 0, _len = faces.length; _i < _len; _i++) {
        f = faces[_i];
        if (f.width > biggest) {
          biggest = f.width;
          face = f;
        }
      }
      if (face !== null && (face.width <= 100 && face.width >= 45)) {
        im.rectangle([face.x, face.y], [face.x + face.width, face.y + face.height], [0, 255, 0], 2);
        center_x = im.width() * 0.5;
        turn = -(face.x - center_x) / center_x;
        console.log("turning: " + turn);
        if (turn < 0) {
          my.drone.clockwise(Math.abs(turn * 0.7));
        } else {
          my.drone.counterClockwise(Math.abs(turn * 0.7));
        }
      }
      my.window.show(im);
    });
    my.drone.takeoff();
    after((8).seconds(), function() { my.drone.up(0.5); });
    after((10).seconds(), function() { my.drone.hover(); });
    after((13).seconds(), function() {
      self.detect = true;
      every(0.3.seconds(), function() {
        my.drone.hover();
        my.mat.detectFaces(self.image, haarcascade);
      });
      after((30).seconds(), function() { my.drone.land(); });
    });
  }
});

Cylon.start();

ARDrone + OpenCV + PS3 Controller + Neurosky

var Cylon = require('cylon');

Cylon.robot({
  connections: [
    {name: 'opencv', adaptor: 'opencv'},
    {name: 'dualshock3', adaptor: 'joystick', controller: 'dualshock3'}, 
    {name: 'ardrone', adaptor: 'ardrone', port: '192.168.1.1'}
  ],
  devices: [
    {name: 'mat', driver: 'mat', conneciton: 'opencv' },
    {name: 'window', driver: 'window', conneciton: 'opencv'},
    {name: 'controller', driver: 'dualshock3', connection: 'dualshock3'}, 
    {name: 'drone', driver: 'ardrone', connection: 'ardrone'}
  ],
  validate_pitch: function(data, offset) {
    var value;
    value = Math.abs(data) / offset;
    if (value >= 0.1) {
      if (value <= 1.0) {
        return Math.round(value * 100.0) / 100.0;
      } else {
        return 1.0;
      }
    } else {
      return 0.0;
    }
  },
  work: function(my) {
    var self = this; 
    self.offset = 125.0;
    self.right_stick = {
      x: self.offset,
      y: self.offset
    };
    self.left_stick = {
      x: self.offset,
      y: self.offset
    };

    my.drone.getPngStream().on('data', function(png) {
      my.mat.readImage(png, function(err, img) {
        my.window.show(img);
      });
    });
    my.controller.on("square:press", function(data) {
      my.drone.takeoff();
    });
    my.controller.on("triangle:press", function(data) { 
      my.drone.hover()
    });
    my.controller.on("x:press", function(data) {
      my.drone.land()
    });
    my.controller.on("right:move", function(data) {
      self.right_stick = data;
    });
    my.controller.on("left:move", function(data) {
      self.left_stick = data;
    });
    every(0, function() {
      var pair;
      pair = self.left_stick;
      if (pair.y < self.offset - 5) {
        my.drone.front(my.validate_pitch(pair.y - self.offset, self.offset));
      } else if (pair.y > self.offset + 5) {
        my.drone.back(my.validate_pitch(pair.y - self.offset, self.offset));
      }
      if (pair.x > self.offset + 5) {
        my.drone.right(my.validate_pitch(pair.x - self.offset, self.offset));
      } else if (pair.x < self.offset - 5) {
        my.drone.left(my.validate_pitch(pair.x - self.offset, self.offset));
      }
    });
    every(0, function() {
      var pair;
      pair = self.right_stick;
      if (pair.y < self.offset - 5) {
        my.drone.up(my.validate_pitch(pair.y - self.offset, self.offset));
      } else if (pair.y > self.offset + 5) {
        my.drone.down(my.validate_pitch(pair.y - self.offset, self.offset));
      }
      if (pair.x > self.offset + 20) {
        my.drone.clockwise(my.validate_pitch(pair.x - self.offset, self.offset));
      } else if (pair.x < self.offset - 20) {
        my.drone.counterClockwise(my.validate_pitch(pair.x - self.offset, self.offset));
      }
    });
    every((0.1).seconds(), my.drone.hover);
  }
});

Cylon.start();
var Cylon = require('cylon');

Cylon.robot({
  connection:
    {name: 'neurosky', adaptor: 'neurosky', port: '/dev/rfcomm0'},

  device:
    {name: 'headset', driver: 'neurosky'},

  work: function(my) {
    my.headset.on('eeg', function(data) {
      Logger.info(data);
    });
  }
});

Cylon.start();

Was that fun?

Join the Robot Evolution!

cylonjs.com

@cylonjs

Thank you!

@deadprogram

@adzankich

#sjsCylon