0

http://wiki.bitplan.com/index.php/Dash describes the Car simulation software https://github.com/mattbradley/dash which I am forking to integrate it with https://github.com/rc-dukes/dukes as asked for in https://github.com/rc-dukes/dukes/issues/37.

The goal is to send the driver image to the rc-dukes software and to allow to control the movements in the simulator from rc-dukes via vert.x bus commands.

When talking to a "real" car - the images are transferred via http as an mjpeg-stream at this point.

Now Dash is a webpack based project and therefore designed to run as a client in the browser even from the file:// protocol.

I'd now like to create a version of it that has Web Server functionality and uses vert.x to communicate with the rest of the rc-dukes project.

First i had the misconception of simple adding a WebServer and using require http and fs which led to quite a few SO questions how to integrate node with WebServer - in the end this doesn't seem to be a good route to go since it would break the original idea of the underlying dash project.

Now i'd like to "optionally" have a server functionality in the project.

Splitting the project into a server / client version does not seem like a good idea.

You'll find the relevant current commit at https://github.com/rc-dukes/dash/commit/ea616a38 The relevant lines

  // import WebServer from "./remote/WebServer"

  //this.videoServer=new WebServer(8234);
  //this.videoServer.start()

are currently commented out

What would be a better design?

My assumption would be that simply sending the images via vert.x would be the best option.

Wolfgang Fahl
  • 15,016
  • 11
  • 93
  • 186

1 Answers1

0

The verticle approach works nicely. Dash file protocol simulator interface RC-Dukes server based interface

Callbacks for heartbeat and sending images

/**
   * call back when a vert.x heartbeat is received
   * @param self - the true this pointer for class Simulator
   * @param heartBeatCount - the number of heart beats received so far
   */
  onHeartBeat(self,heartBeatCount) {
    var color=heartBeatCount/3%2==0?"white":"purple";
    self.setColorAndTitle("heartbeat-icon",color,heartBeatCount.toString());
    // reply with the current image
    self.onSendImage(self);
  }

  /**
   * call back to send current Three.js canvas over the vert.x wire
   * @param self - the true this pointer for class Simulator
   */
  onSendImage(self) {
    // https://stackoverflow.com/a/26197858/1497139
    var strMime = "image/jpeg";
    var imgData = this.renderer.domElement.toDataURL(strMime);
    self.remoteController.sendImage(imgData);
  }

Vert.x javascript Verticle to communicate with Java Server side

// part of https://github.com/rc-dukes/dash fork of https://github.com/mattbradley/dash

const CALLSIGN_FLASH = "Velvet ears"; // Watchdog
const CALLSIGN_BO = "Lost sheep Bo";  // Car
const CALLSIGN_ROSCO = "Red Dog"; // Debug ImageView server
var simulatorVerticle = null;

/**
 * SimulatorVerticle to be used as remoteController
 */
export default class SimulatorVerticle {

  /**
   * construct me
   * @param busUrl
   * @param self
   * @param onHeartBeat
   */
  constructor(busUrl,self=null,onHeartBeat=null) {
    this.busUrl=busUrl;
    this.self=self;
    this.onHeartBeat=onHeartBeat;
    this.heartBeatCount=0;
    this.debugHeartBeat=true;
    this.remoteControl=new RemoteControl();
    simulatorVerticle=this;
    this.enabled=false;
  }

  /**
   * all publish messages should go thru this function
   *
   * @param address
   * @param message
   * @param headers
   */
  publish(address,message,headers) {
    if (this.eb.state===EventBus.OPEN)
      this.eb.publish(address, message, headers);
  };

  /**
   * send the given image to the debug image server
   * @param imgData
   */
  sendImage(imgData) {
    this.publish(CALLSIGN_ROSCO+":SIMULATOR_IMAGE",imgData);
  }

  /**
   * start the verticle and register the handlers
   */
  start() {
    if (!this.eb) {
      this.eb = new EventBus(this.busUrl);
      this.eb.onopen = function() {
        simulatorVerticle.eb.registerHandler(CALLSIGN_FLASH,simulatorVerticle.heartBeatHandler);
        simulatorVerticle.eb.registerHandler(CALLSIGN_BO,simulatorVerticle.carMessageHandler)
      };
    };
    this.enabled=true;
  }

  stop() {
    if (this.eb)
      this.eb.close();
    this.eb=null;
    this.enabled=false;
  }

  /**
   * handle a car message
   * @param err - potential errors
   * @param msg - the vert.x message
   */
  carMessageHandler(err,msg) {
    var carjo=msg.body;
    console.log(JSON.stringify(carjo));
    var sv=simulatorVerticle;
    switch (carjo.type) {
      case 'servodirect':
        if (carjo.position) {
          // the position can be between -100 and 100
          var pos=parseFloat(carjo.position);
          // we need a value between -1 and +1
          sv.remoteControl.steer=pos/100;
        }
      break;
      case 'servo':
         switch (carjo.position) {
           case 'left':
             sv.remoteControl.steer-=0.01;
           break;
           case 'right':
             sv.remoteControl.steer+=0.01;
           break;
           case 'center':
             sv.remoteControl.steer=0;
           break;
         }
      break;
      case 'motor':
         switch (carjo.speed) {
           case 'up':
             sv.remoteControl.gas+=0.01;
           break;
           case 'down':
             sv.remoteControl.gas-=0.01;
           break;
           case 'brake':
             sv.remoteControl.break+=0.01;
           break;
           case 'stop':
             sv.remoteControl.gas=0;
             sv.remoteControl.break=1;
           break;
         }
      break;
    }
  }

  /**
   * handle a heart beat message
   * @param err - potential errors
   * @param msg - the vert.x message
   */
  heartBeatHandler(err,msg) {
    var jo=msg.body;
    var sv=simulatorVerticle;
    if (sv.debugHeartBeat)
       console.log(JSON.stringify(jo));
    sv.heartBeatCount++;
    if (sv.onHeartBeat && sv.self) {
      sv.onHeartBeat(sv.self,sv.heartBeatCount);
    }
  }

  stateColor() {
    var stateColor = "white";
    if (this.eb) {
      switch (this.eb.state) {
      case EventBus.CONNECTING:
        stateColor = "orange";
        break;
      case EventBus.OPEN:
        stateColor = "green";
        break;
      case EventBus.CLOSING:
        stateColor = "orange";
        break;
      case EventBus.CLOSED:
        stateColor = "red";
        break;
      }
    } else {
      stateColor = "violet";
    }
    return stateColor;
  }
}

export class RemoteControl {
  /**
   * @param gas
   * @param brake
   * @param steer
   */
  constructor(gas=0,brake=0,steer=0) {
    this.gas=0;
    this.brake=0;
    this.steer=0;
  }
}
Wolfgang Fahl
  • 15,016
  • 11
  • 93
  • 186