diff --git a/car_srv/src/Car.js b/car_srv/src/Car.js new file mode 100644 index 00000000000..396e8b63480 --- /dev/null +++ b/car_srv/src/Car.js @@ -0,0 +1,152 @@ +/** + * Created by user on 7/21/16. + */ + +const fs = require("fs"); +const main = require("./main.js"); +const directionClass = main.protoConstructorControl.DirectionRequest; + +function Car(uid) { + this.uid = uid; + this.x = 0; + this.y = 0; + this.angle = 0; + this.velocityMove = 0.1; + this.velocityRotation = 10; + this.paused = false; + this.transportError = false; + this.currentDirection = 0; + this.executeTimeLeft = 0; + this.moveList = [];//object of direction and time to execute this direction. field: direction:byte, executeTime:double (seconds) + this.nextMoveListIndex = 0; + + this.reset = reset; + this.pause = pause; + this.move = move; + this.setDirection = setDirection; + this.resume = resume; + this.getDirectionByte = getDirectionByte; + this.setPath = setPath; + + return this; +} +function reset() { + this.currentDirection = 0; + this.executeTimeLeft = 0; + this.moveList = []; + this.nextMoveListIndex = 0; +} + +function pause() { + this.paused = true; +} + +function resume() { + this.paused = false; +} + +function move(delta) { + var deltaSeconds = delta / 1000; + // console.log("x=" + this.x + " y=" + this.y + " angle=" + this.angle); + if (this.paused) { + return; + } + if (this.executeTimeLeft > 0) { + this.executeTimeLeft -= deltaSeconds; + if (this.currentDirection == this.getDirectionByte(directionClass.Command.left)) { + this.angle += deltaSeconds * this.velocityRotation; + } else if (this.currentDirection == this.getDirectionByte(directionClass.Command.right)) { + this.angle -= deltaSeconds * this.velocityRotation; + } else if (this.currentDirection == this.getDirectionByte(directionClass.Command.forward)) { + this.x += this.velocityMove * deltaSeconds * Math.cos(this.angle * Math.PI / 180); + this.y += this.velocityMove * deltaSeconds * Math.sin(this.angle * Math.PI / 180); + } + } else { + if (this.nextMoveListIndex == this.moveList.length) { + //this was last move point + this.setDirection(this.getDirectionByte(directionClass.Command.stop), null) + } else { + var currentMove = this.moveList[this.nextMoveListIndex]; + this.currentDirection = currentMove.direction; + this.executeTimeLeft = currentMove.executeTime; + this.setDirection(this.currentDirection, null); + this.nextMoveListIndex++; + } + } +} + +//args wayPointsList contains object of points. field {distance, angle_delta}. this fun parse this to move list with field direction and move time with using velocity of move and rotation +function setPath(wayPointsList) { + this.reset(); + for (var i = 0; i < wayPointsList.length; i++) { + var currentPoint = wayPointsList[i]; + var angle = currentPoint.angle_delta; + var distance = currentPoint.distance; + if (angle != 0) { + //need rotation. check direction left or right + if (angle >= 180) { + this.moveList.push({ + "direction": getDirectionByte(directionClass.Command.right), + "executeTime": (angle / this.velocityRotation) + }); + } else { + this.moveList.push({ + "direction": getDirectionByte(directionClass.Command.left), + "executeTime": (angle / this.velocityRotation) + }); + } + } + this.moveList.push({ + "direction": getDirectionByte(directionClass.Command.forward), + "executeTime": (distance / this.velocityMove) + }); + } +} + +function setDirection(directionByte, callBack) { + fs.appendFile(main.transportFilePath, directionByte, "binary", function (error) { + var code = 0; + var errorMsg = ""; + console.log(error); + if (error) { + errorMsg = error; + } + if (callBack != null) { + callBack(code, errorMsg) + } + }); +} + +function getDirectionByte(command) { + resultByte = -1; + switch (command) { + case directionClass.Command.stop: + { + resultByte = "0"; + break; + } + case directionClass.Command.forward: + { + resultByte = "1"; + break; + } + case directionClass.Command.backward: + { + resultByte = "2"; + break; + } + case directionClass.Command.right: + { + resultByte = "3"; + break; + } + case directionClass.Command.left: + { + resultByte = "4"; + break; + } + } + return resultByte +} + +exports.getCar = Car; \ No newline at end of file diff --git a/car_srv/src/handlers.js b/car_srv/src/handlers.js deleted file mode 100644 index efd48acd99e..00000000000 --- a/car_srv/src/handlers.js +++ /dev/null @@ -1,100 +0,0 @@ -/** - * Created by user on 7/11/16. - */ -const fs = require("fs"); -const main = require("./main.js"); -const exec = require('child_process').exec; - -function loadBin(httpContent, response) { - var uploadClass = main.protoConstructorCarkot.Upload; - var uploadObject = uploadClass.decode(httpContent); - fs.writeFile(main.binFilePath, uploadObject.data.buffer, "binary", function (error) { - var uploadResultClass = main.protoConstructorCarkot.UploadResult; - var code = 0; - var stdErr = ""; - if (error) { - code = 2; - stdErr = error.toString(); - } else { - code = 0; - var shCommand = main.commandPrefix + " " + main.binFilePath + " " + uploadObject.base; - exec(shCommand, function (error, stdout, stderr) { - if (error) { - code = 1; - console.error(error); - } - - var resultObject = new uploadResultClass({ - "stdOut": stdout.toString(), - "resultCode": code, - "stdErr": (stderr.toString() + "\n error:" + error) - }); - var byteBuffer = resultObject.encode(); - var byteArray = []; - for (var i = 0; i < byteBuffer.limit; i++) { - byteArray.push(byteBuffer.buffer[i]); - } - response.writeHead(200, {"Content-Type": "text/plain", "Content-length": byteArray.length}); - response.write(new Buffer(byteArray)); - response.end(); - console.log(shCommand); - }); - } - - }); -} - -function other(httpContent, response) { - console.log("other"); - response.writeHead(200, {"Content-Type": "text/plain"}); - response.end(); -} - -//контроль машинкой, как с пульта управления -function control(httpContent, response) { - var directionClass = main.protoConstructorControl.Direction; - var directionObject = directionClass.decode(httpContent); - var resultByte; - switch (directionObject.command) { - case directionClass.Command.stop : - { - resultByte = "0"; - break; - } - case directionClass.Command.forward : - { - resultByte = "1"; - break; - } - - case directionClass.Command.backward : - { - resultByte = "2"; - break; - } - case directionClass.Command.right : - { - resultByte = "3"; - break; - } - case directionClass.Command.left : - { - resultByte = "4"; - break; - } - } - console.log("byte for car: " + resultByte); - fs.appendFile(main.transportFilePath, resultByte, "binary", function (error) { - if (error) { - console.log(error); - } - //todo ещё нужно считывать ответ от контроллера и анализировать его (0 или 1) и отправлять - response.writeHead(200, {"Content-Type": "text/plain"}); - response.write(new Buffer([0])); - response.end(); - }); -} - -exports.loadBin = loadBin; -exports.other = other; -exports.control = control; diff --git a/car_srv/src/handlers/controlHandler.js b/car_srv/src/handlers/controlHandler.js new file mode 100644 index 00000000000..4ac6deaa140 --- /dev/null +++ b/car_srv/src/handlers/controlHandler.js @@ -0,0 +1,40 @@ +/** + * Created by user on 7/21/16. + */ + +const main = require("./../main.js"); + +function handle(httpContent, response) { + var directionClass = main.protoConstructorControl.DirectionRequest; + var directionObject = directionClass.decode(httpContent); + var resultByte = main.thisCar.getDirectionByte(directionObject.command); + main.thisCar.reset(); + main.thisCar.moveList.push({ + "direction": resultByte, + "executeTime": 100000 + }); + console.log(resultByte); + var directionResponse = new main.protoConstructorControl.DirectionResponse({ + "code": 0, + errorMsg: "" + }); + var byteBuffer = directionResponse.encode(); + var byteArray = []; + for (var i = 0; i < byteBuffer.limit; i++) { + byteArray.push(byteBuffer.buffer[i]); + } + response.writeHead(200, {"Content-Type": "text/plain"}); + response.write(new Buffer(byteArray)); + response.end(); + // main.thisCar.setDirection(resultByte, function (code, errorMsg) { + // var directionResponse = new main.protoConstructorControl.DirectionResponse({ + // "code": code, + // errorMsg: errorMsg + // }); + // response.writeHead(200, {"Content-Type": "text/plain"}); + // response.write(directionResponse.encode().buffer); + // response.end(); + // }); +} + +exports.handler = handle; \ No newline at end of file diff --git a/car_srv/src/handlers/loadBinHandler.js b/car_srv/src/handlers/loadBinHandler.js new file mode 100644 index 00000000000..3fa6e30602a --- /dev/null +++ b/car_srv/src/handlers/loadBinHandler.js @@ -0,0 +1,48 @@ +/** + * Created by user on 7/21/16. + */ + +const fs = require("fs"); +const main = require("./../main.js"); +const exec = require('child_process').exec; + +function handle(httpContent, response) { + var uploadClass = main.protoConstructorCarkot.Upload; + var uploadObject = uploadClass.decode(httpContent); + fs.writeFile(main.binFilePath, uploadObject.data.buffer, "binary", function (error) { + var uploadResultClass = main.protoConstructorCarkot.UploadResult; + var code = 0; + var stdErr = ""; + if (error) { + code = 2; + stdErr = error.toString(); + } else { + code = 0; + var shCommand = main.commandPrefix + " " + main.binFilePath + " " + uploadObject.base; + exec(shCommand, function (error, stdout, stderr) { + if (error) { + code = 1; + console.error(error); + } + + var resultObject = new uploadResultClass({ + "stdOut": stdout.toString(), + "resultCode": code, + "stdErr": (stderr.toString() + "\n error:" + error) + }); + var byteBuffer = resultObject.encode(); + var byteArray = []; + for (var i = 0; i < byteBuffer.limit; i++) { + byteArray.push(byteBuffer.buffer[i]); + } + response.writeHead(200, {"Content-Type": "text/plain", "Content-length": byteArray.length}); + response.write(new Buffer(byteArray)); + response.end(); + console.log(shCommand); + }); + } + + }); +} + +exports.handler = handle; \ No newline at end of file diff --git a/car_srv/src/handlers/setRouteHandler.js b/car_srv/src/handlers/setRouteHandler.js new file mode 100644 index 00000000000..e12d025c2a3 --- /dev/null +++ b/car_srv/src/handlers/setRouteHandler.js @@ -0,0 +1,13 @@ +/** + * Created by user on 7/21/16. + */ + +const main = require("./../main.js"); + +function handle(httpContent, response) { + var routeClass = main.protoConstructorRoute.RouteRequest; + var routeObject = routeClass.decode(httpContent); + console.log(routeObject)//todo сделать +} + +exports.handler = handle; \ No newline at end of file diff --git a/car_srv/src/main.js b/car_srv/src/main.js index 98432e0567f..f6a39e7836d 100644 --- a/car_srv/src/main.js +++ b/car_srv/src/main.js @@ -1,5 +1,5 @@ /** - * Created by user on 7/11/16. + * Created by maxim zaitsev on 7/11/16. */ const server = require("./server.js"); @@ -9,11 +9,12 @@ const protoBuf = require("protobufjs"); const fs = require("fs"); const udev = require("udev"); +//parsing command line args commander .version('1.0.0') .option('-p, --proto [path]', 'path to dir with proto files. need here carkot.proto and route.proto. default ./proto/') - .option('-f, --flash [path]', 'path to save bin file with name f.bin. default ./') - .option('-s, --serial [path]', 'path to file that represents MCU serial port default ./serial') + .option('-f, --flash [path]', 'path to save bin file with name flash.bin. default ./') + // .option('-s, --serial [path]', 'path to file that represents MCU serial port default ./serial')//dont need more. use path from udev monitor .parse(process.argv); //add slash to end of paths if need @@ -28,30 +29,38 @@ if (commander.flash) { } } -const builderCarkot = protoBuf.loadProtoFile(commander.protopath ? commander.protopath + "carkot.proto" : "./proto/carkot.proto"); -const builderControl = protoBuf.loadProtoFile(commander.protopath ? commander.protopath + "route.proto" : "./proto/route.proto"); +//classes for protobuf decode/encode +const builderCarkot = protoBuf.loadProtoFile((commander.protopath ? commander.protopath : "./proto/") + "carkot.proto"); +const builderControl = protoBuf.loadProtoFile((commander.protopath ? commander.protopath : "./proto/" + "direction.proto")); +const builderRoute = protoBuf.loadProtoFile((commander.protopath ? commander.protopath : "./proto/" + "route.proto")); var executeShell = "./st-flash"; exports.protoConstructorCarkot = builderCarkot.build("carkot"); exports.protoConstructorControl = builderControl.build("carkot"); +exports.protoConstructorRoute = builderRoute.build("carkot"); exports.commandPrefix = executeShell + " write"; -exports.binFilePath = (commander.flash ? commander.flash : "./") + "st-flash"; -exports.transportFilePath = (commander.serial ? commander.serial : "./serial"); +exports.binFilePath = (commander.flash ? commander.flash : "./") + "flash.bin"; +exports.transportFilePath = ""; -var handlers = require("./handlers.js"); +//init this car +var uid = "";//todo connect to srv +var car = require("./Car").getCar(uid); +exports.thisCar = car; + +//handlers for client requests var handle = {}; -handle["/"] = handlers.other; -handle["/loadBin"] = handlers.loadBin; -handle["/control"] = handlers.control; -handle["/other"] = handlers.other; - -//add handlers to events from udev monitor (add device and remove device) +handle["/loadBin"] = require("./handlers/loadBinHandler").handler; +handle["/control"] = require("./handlers/controlHandler").handler; +handle["/route"] = require("./handlers/setRouteHandler").handler; +exports.transportFilePath = "/dev/ttyACM0"; +//add event handlers from udev monitor (add device and remove device) const monitor = udev.monitor(); monitor.on('add', function (device) { if (device.ID_VENDOR_ID == "0483" && device.ID_MODEL_ID == "5740" && device.SUBSYSTEM == "tty") { //mc connected - console.log("connected"); - console.log("file=" + device.DEVNAME) + console.log("connected. transport file is " + device.DEVNAME); + exports.transportFilePath = device.DEVNAME; + console.log(device.DEVNAME); } }); monitor.on('remove', function (device) { @@ -61,6 +70,7 @@ monitor.on('remove', function (device) { } }); +//check of exists st-flash util if (typeof fs.access == "function") { fs.access(executeShell, fs.F_OK, function (error) { if (!error) { @@ -73,4 +83,10 @@ if (typeof fs.access == "function") { console.log("warning: you have old version of node.js. Check existence of the file st-flash on root of server dir yourself"); server.start(router.route, handle); } -// server.start(router.route, handle); + +//move car +var delta = 100; +setInterval(moveCar, delta); +function moveCar() { + car.move(delta) +} \ No newline at end of file diff --git a/car_srv/src/package.json b/car_srv/src/package.json index 38ecf0cb442..f0ed83361da 100644 --- a/car_srv/src/package.json +++ b/car_srv/src/package.json @@ -9,7 +9,8 @@ }, "author": "maxim", "license": "ISC", - "dependencies": { + "devDependencies": { + "udev": "^0.3.0", "commander": "^2.9.0", "protobufjs": "^5.0.1" } diff --git a/car_srv/src/proto/connect.proto b/car_srv/src/proto/connect.proto new file mode 100644 index 00000000000..49df5b9aaa9 --- /dev/null +++ b/car_srv/src/proto/connect.proto @@ -0,0 +1,17 @@ +syntax = "proto3"; +package carkot; + +option java_package = "proto.car"; +option java_outer_classname = "Connect"; + +message ConnectionRequest { + string ip = 1; + int32 port = 2; +} + +message ConnectionResponse { + int32 uid = 1; + int32 code = 2; + string errorMsg = 3; + +} diff --git a/car_srv/src/proto/direction.proto b/car_srv/src/proto/direction.proto new file mode 100644 index 00000000000..ca614a16ea6 --- /dev/null +++ b/car_srv/src/proto/direction.proto @@ -0,0 +1,21 @@ +syntax = "proto3"; +package carkot; + +option java_package = "proto.car"; +option java_outer_classname = "Direction"; + +message DirectionRequest { + enum Command { + stop = 0; + forward = 1; + backward = 2; + left = 3; + right = 4; + } + Command command = 1; +} + +message DirectionResponse { + int32 code = 1; + string errorMsg = 2; +} diff --git a/car_srv/src/proto/location.proto b/car_srv/src/proto/location.proto new file mode 100644 index 00000000000..0d477c8217e --- /dev/null +++ b/car_srv/src/proto/location.proto @@ -0,0 +1,18 @@ +syntax = "proto3"; +package carkot; + +option java_package = "proto.car"; +option java_outer_classname = "Location"; + +message LocationResponse { + + LocationData locationResponseData = 1; + int32 code = 2; + string errorMsg = 3; + + message LocationData { + double x = 1; + double y = 2; + double angle = 3; + } +} diff --git a/car_srv/src/proto/route.proto b/car_srv/src/proto/route.proto index 50ac625c415..864845be2f0 100644 --- a/car_srv/src/proto/route.proto +++ b/car_srv/src/proto/route.proto @@ -2,10 +2,10 @@ syntax = "proto3"; package carkot; option java_package = "proto.car"; -option java_outer_classname = "RouteP"; +option java_outer_classname = "Route"; -message Route { - repeated WayPoint way_points = 1; +message RouteRequest { + repeated WayPoint way_points = 1; message WayPoint { double distance = 2; @@ -13,13 +13,7 @@ message Route { } } -message Direction { - enum Command { - stop = 0; - forward = 1; - backward = 2; - left = 3; - right = 4; - } - Command command = 1; +message RouteResponse { + int32 code = 1; + string errorMsg = 2; } diff --git a/car_srv/src/proto/route_done.proto b/car_srv/src/proto/route_done.proto new file mode 100644 index 00000000000..5fe75d274f2 --- /dev/null +++ b/car_srv/src/proto/route_done.proto @@ -0,0 +1,10 @@ +syntax = "proto3"; +package carkot; + +option java_package = "proto.car"; +option java_outer_classname = "RouteDone"; + +message RouteDoneResponse { + int32 code = 1; + string errorMsg = 2; +}