main server refactoring

This commit is contained in:
MaximZaitsev
2016-09-05 13:09:49 +03:00
parent 191a65bede
commit a589f7da9c
30 changed files with 524 additions and 497 deletions
-285
View File
@@ -1,285 +0,0 @@
import RoomScanner.serialize
import algorithm.AbstractAlgorithm
import algorithm.AlgorithmThread
import algorithm.RoomBypassingAlgorithm
import algorithm.RoomModel
import net.car.client.Client
import objects.Car
import objects.Environment
import java.net.ConnectException
import java.rmi.UnexpectedException
object DebugClInterface {
//todo remove
var algorithmImpl: AbstractAlgorithm? = null
var algorithmThread: AlgorithmThread? = null
private val routeRegex = Regex("route [0-9]{1,10}")
private val sonarRegex = Regex("sonar [0-9]{1,10}")
private val helpString = "available handlers:\n" +
"cars - get list of connected cars\n" +
"route [car_id] - setting a route for net.car with net.car id.\n" +
"sonar [car_id] - get sonar data\n" +
"dbinfo [car_id] [type] - refresh all net.car locations\n" +
"lines - print lines, detected by net.car\n" +
"alg [count] - run algorithm. Make [count] iteration\n" +
"type is string name of value or int value. available values: MEMORYSTATS - 0\n" +
"stop - exit from this interface and stop all threads\n"
fun run() {
println(helpString)
while (true) {
val readString = readLine()
if (readString == null || readString.equals("stop")) {
break
}
if (readString.equals("")) {
continue
}
try {
executeCommand(readString)
} catch (exception: Exception) {
exception.printStackTrace()
println("Fail to execute command[$readString]: $exception")
}
}
}
private fun printNotSupportedCommand(command: String) {
println("not supported command: $command")
println(helpString)
}
private fun executeCommand(readString: String) {
val commandType = readString.split(" ")[0].toLowerCase()
when (commandType) {
"cars" -> {
synchronized(Environment, {
println(Environment.map.values)
})
}
"route" -> executeRouteCommand(readString)
"sonar" -> executeSonarCommand(readString)
"dbinfo" -> executeDebugInfoCommand(readString)
"lines" -> algorithm.RoomModel.walls.forEach { println(it.line) }
"pos" -> {
val tmp = algorithmImpl
if (tmp is RoomBypassingAlgorithm) {
println("walls: ${RoomModel.walls}")
println("x: ${tmp.thisCar.x} y: ${tmp.thisCar.y} angle:${tmp.thisCar.angle}")
}
}
"alg" -> executeAlg(readString)
"explore" -> executeExplore(readString)
else -> printNotSupportedCommand(readString)
}
}
private fun executeExplore(readString: String) {
val params = readString.split(" ")
val car = Environment.map[params[1].toInt()]!!
val angle = params[2].toInt()
val window = params[3].toInt()
val request = SonarExploreAngleRequest.BuilderSonarExploreAngleRequest(angle, window).build()
val responseData = car.carConnection.sendRequest(
Client.Request.EXPLORE_ANGLE,
serialize(request.getSizeNoTag(), { request.writeTo(it) })
).get().responseBodyAsBytes
val distances = SonarExploreAngleResponse.BuilderSonarExploreAngleResponse(IntArray(0)).parseFrom(CodedInputStream(responseData)).build().distances
println("Received distances: [${distances.joinToString()}]")
}
private fun executeAlg(readString: String) {
val params = readString.split(" ")
val count =
if (params.size == 2) try {
params[1].toInt()
} catch (e: Exception) {
1
} else 1
var alg = algorithmImpl
if (alg == null) {
alg = RoomBypassingAlgorithm(Environment.map.values.last())
}
var algThread = algorithmThread
if (algThread == null) {
algThread = AlgorithmThread(alg)
algThread.start()
}
algorithmImpl = alg
algThread.setCount(count)
algorithmThread = algThread
}
private fun executeDebugInfoCommand(readString: String) {
val params = readString.split(" ")
val car = Environment.map[params[1].toInt()]!!
val type = DebugRequest.Type.fromIntToType(params[2].toInt())
val request = DebugRequest.BuilderDebugRequest(type).build()
val requestType = when (type) {
DebugRequest.Type.MEMORY_STATS -> Client.Request.DEBUG_MEMORY
DebugRequest.Type.SONAR_STATS -> Client.Request.DEBUG_SONAR
else -> throw UnexpectedException(type.toString())
}
val responseData = car.carConnection.sendRequest(
requestType,
serialize(request.getSizeNoTag(), { request.writeTo(it) })
).get().responseBodyAsBytes
when (type) {
DebugRequest.Type.MEMORY_STATS -> {
val data = DebugResponseMemoryStats.BuilderDebugResponseMemoryStats(0, 0, 0, 0).parseFrom(CodedInputStream(responseData)).build()
println("Heap static tail: ${data.heapStaticTail}")
println("Heap dynamic tail: ${data.heapDynamicTail}")
println("Heap dynamic max size: ${data.heapDynamicMaxBytes}")
println("Heap dynamic total size: ${data.heapDynamicTotalBytes}")
}
DebugRequest.Type.SONAR_STATS -> {
val data = DebugResponseSonarStats.BuilderDebugResponseSonarStats(0, 0, 0, 0).parseFrom(CodedInputStream(responseData)).build()
println("Sonar measurement total: ${data.measurementCount}")
println("Failed checksums: ${data.measurementFailedChecksum}")
println("Failed command: ${data.measurementFailedCommand}")
println("Failed distance: ${data.measurementFailedDistance}")
}
else -> throw UnexpectedException(type.toString())
}
}
private fun executeSonarCommand(readString: String) {
if (!sonarRegex.matches(readString)) {
println("incorrect args of command sonar.")
println(helpString)
return
}
val id: Int
try {
id = readString.split(" ")[1].toInt()
} catch (e: NumberFormatException) {
e.printStackTrace()
println("error in converting id to int type")
println(helpString)
return
}
val car: Car? = synchronized(Environment, {
Environment.map[id]
})
if (car == null) {
println("net.car with id=$id not found")
return
}
val requestMessage = getSonarRequest() ?: return
val requestBytes = ByteArray(requestMessage.getSizeNoTag())
requestMessage.writeTo(CodedOutputStream(requestBytes))
try {
car.carConnection.sendRequest(Client.Request.SONAR, requestBytes)
} catch (e: ConnectException) {
synchronized(Environment, {
Environment.map.remove(id)
})
}
}
private fun getSonarRequest(): SonarRequest? {
println("print angles, after printing all angles print done")
val angles = arrayListOf<Int>()
while (true) {
val command = readLine()!!.toLowerCase()
when (command) {
"reset" -> return null
"done" -> {
val sonarBuilder = SonarRequest.BuilderSonarRequest(angles.toIntArray(), IntArray(angles.size, { 5 }), 3, SonarRequest.Smoothing.MEDIAN)
return sonarBuilder.build()
}
else -> {
try {
val angle = command.toInt()
if (angle < 0 || angle > 180) {
println("incorrect angle $angle. angle must be in [0,180] and div on 4")
} else {
angles.add(angle)
}
} catch (e: NumberFormatException) {
println("error in converting angle to int. try again")
}
}
}
}
}
private fun executeRouteCommand(readString: String) {
if (!routeRegex.matches(readString)) {
println("incorrect args of command route.")
println(helpString)
return
}
val id: Int
try {
id = readString.split(" ")[1].toInt()
} catch (e: NumberFormatException) {
e.printStackTrace()
println("error in converting id to int type")
println(helpString)
return
}
val car: Car? =
synchronized(Environment, {
Environment.map[id]
})
if (car == null) {
println("net.car with id=$id not found")
return
}
val routeMessage = getRouteMessage() ?: return
val requestBytes = ByteArray(routeMessage.getSizeNoTag())
routeMessage.writeTo(CodedOutputStream(requestBytes))
try {
car.carConnection.sendRequest(Client.Request.ROUTE_METRIC, requestBytes)
} catch (e: ConnectException) {
synchronized(Environment, {
Environment.map.remove(id)
})
}
}
private fun getRouteMessage(): RouteRequest? {
println("print way points in polar coordinate als [distance/degrees] [direction] in sm and degrees." +
"after enter all points print \"done\". for reset route print \"reset\". available directions:" +
"0 - FORWARD, 1 - BACKWARD, 2 - LEFT, 3 - RIGHT")
val distances = arrayListOf<Int>()
val angles = arrayListOf<Int>()
while (true) {
val readLine = readLine()!!.toLowerCase()
when (readLine) {
"reset" -> return null
"done" -> {
val routeBuilder = RouteRequest.BuilderRouteRequest(distances.toIntArray(), angles.toIntArray())
return routeBuilder.build()
}
else -> {
val wayPointData = readLine.split(" ")
val distance: Int
val angle: Int
try {
distance = wayPointData[0].toInt()
angle = wayPointData[1].toInt()
distances.add(distance)
angles.add(angle)
} catch (e: NumberFormatException) {
println("error in converting target or distance to int. try again")
} catch (e: IndexOutOfBoundsException) {
println("format error, u must print two number separated by spaces. Try again")
}
}
}
}
}
}
+3 -3
View File
@@ -1,6 +1,5 @@
import java.io.BufferedWriter import java.io.BufferedWriter
import java.io.File import java.io.File
import java.io.FileOutputStream
import java.io.FileWriter import java.io.FileWriter
object Logger { object Logger {
@@ -14,12 +13,13 @@ object Logger {
padding += paddingStep padding += paddingStep
} }
fun outdent() { fun outDent() {
if (padding.length == 0) { if (padding.length == 0) {
throw IllegalArgumentException("Called outdent without corresponsing indent") throw IllegalArgumentException("Called out dent without corresponding indent")
} }
padding = padding.removeSuffix(paddingStep) padding = padding.removeSuffix(paddingStep)
} }
fun log(msg: String) { fun log(msg: String) {
bufferedWriter.write(padding + msg + "\n") bufferedWriter.write(padding + msg + "\n")
bufferedWriter.flush() bufferedWriter.flush()
+3 -5
View File
@@ -1,5 +1,6 @@
import RoomScanner.CarController import roomScanner.CarController
import RoomScanner.RoomScanner import roomScanner.RoomScanner
import clInterface.DebugClInterface
import net.car.Dropper import net.car.Dropper
import net.car.client.Client import net.car.client.Client
import objects.Environment import objects.Environment
@@ -20,9 +21,6 @@ fun main(args: Array<String>) {
} }
} }
//todo запуск потока алгоритма нужно вынести сюда,
//todo а debug интерфейсутребуется исключительно возможность установки кол-ва итераций
//CL user interface
DebugClInterface.run() DebugClInterface.run()
carsDestroy.interrupt() carsDestroy.interrupt()
@@ -1,19 +1,13 @@
package algorithm package algorithm
import CodedInputStream
import CodedOutputStream
import Logger import Logger
import RouteMetricRequest import RouteMetricRequest
import SonarRequest import SonarRequest
import SonarResponse
import algorithm.geometry.Angle import algorithm.geometry.Angle
import algorithm.geometry.AngleData import algorithm.geometry.AngleData
import net.car.client.Client
import objects.Car import objects.Car
import java.net.ConnectException import roomScanner.CarController.Direction.*
import java.util.* import java.util.*
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeoutException
abstract class AbstractAlgorithm(val thisCar: Car) { abstract class AbstractAlgorithm(val thisCar: Car) {
@@ -21,11 +15,7 @@ abstract class AbstractAlgorithm(val thisCar: Car) {
open val SMOOTHING = SonarRequest.Smoothing.NONE open val SMOOTHING = SonarRequest.Smoothing.NONE
open val WINDOW_SIZE = 0 open val WINDOW_SIZE = 0
protected val FORWARD = 0 val carController = CarController(thisCar.carConnection)
protected val BACKWARD = 1
protected val LEFT = 2
protected val RIGHT = 3
private val historySize = 10 private val historySize = 10
private val history = Stack<RouteMetricRequest>() private val history = Stack<RouteMetricRequest>()
@@ -44,50 +34,6 @@ abstract class AbstractAlgorithm(val thisCar: Car) {
private var iterationCounter = 0 private var iterationCounter = 0
protected fun getData(angles: Array<Angle>): IntArray {
val anglesIntArray = (angles.map { it -> it.degs() }).toIntArray()
val message = SonarRequest.BuilderSonarRequest(
angles = anglesIntArray,
attempts = IntArray(angles.size, { ATTEMPTS }),
smoothing = SMOOTHING,
windowSize = WINDOW_SIZE)
.build()
val requestBytes = ByteArray(message.getSizeNoTag())
message.writeTo(CodedOutputStream(requestBytes))
try {
val futureListener = thisCar.carConnection.sendRequest(Client.Request.SONAR, requestBytes)
val bytes = futureListener.get(300, TimeUnit.SECONDS).responseBodyAsBytes
val responseMessage = SonarResponse.BuilderSonarResponse(IntArray(0)).build()
responseMessage.mergeFrom(CodedInputStream(bytes))
return responseMessage.distances
} catch (e: ConnectException) {
println("connection error!")
} catch (e: TimeoutException) {
println("don't have response from net.car. Timeout!")
}
return IntArray(0)
}
//todo методы управления машинкой должны быть в отдельном классе по аналогии с carController
protected fun moveCar(message: RouteMetricRequest) {
val requestBytes = ByteArray(message.getSizeNoTag())
message.writeTo(CodedOutputStream(requestBytes))
moveCar(requestBytes)
}
private fun moveCar(messageBytes: ByteArray) {
try {
thisCar.carConnection.sendRequest(Client.Request.ROUTE_METRIC, messageBytes).get(60, TimeUnit.SECONDS)
} catch (e: ConnectException) {
println("connection error!")
} catch (e: TimeoutException) {
println("don't have response from net.car. Timeout!")
}
return
}
fun iterate() { fun iterate() {
Logger.log("============= STARTING ITERATION $iterationCounter ============") Logger.log("============= STARTING ITERATION $iterationCounter ============")
Logger.indent() Logger.indent()
@@ -96,7 +42,7 @@ abstract class AbstractAlgorithm(val thisCar: Car) {
return return
} }
val angles = getAngles() val angles = getAngles()
val distances = getData(angles) val distances = carController.scan(angles.map { it.degs() }.toIntArray(), ATTEMPTS, WINDOW_SIZE, SMOOTHING)
if (distances.size != angles.size) { if (distances.size != angles.size) {
throw RuntimeException("error! angles and distances have various sizes") throw RuntimeException("error! angles and distances have various sizes")
} }
@@ -126,22 +72,22 @@ abstract class AbstractAlgorithm(val thisCar: Car) {
Logger.indent() Logger.indent()
Logger.log("Directions = ${Arrays.toString(command.directions)}") Logger.log("Directions = ${Arrays.toString(command.directions)}")
Logger.log("Distanced = ${Arrays.toString(command.distances)}") Logger.log("Distanced = ${Arrays.toString(command.distances)}")
Logger.outdent() Logger.outDent()
println(Arrays.toString(command.directions)) println(Arrays.toString(command.directions))
println(Arrays.toString(command.distances)) println(Arrays.toString(command.distances))
this.prevSonarDistances = anglesDistances this.prevSonarDistances = anglesDistances
this.prevState = state this.prevState = state
moveCar(command) carController.moveCar(command)
Logger.outdent() Logger.outDent()
Logger.log("============= FINISHING ITERATION $iterationCounter ============") Logger.log("============= FINISHING ITERATION $iterationCounter ============")
Logger.log("") Logger.log("")
} }
private fun addCancelIterationToLog() { private fun addCancelIterationToLog() {
Logger.log("iteration cancelled. need more data from sonar") Logger.log("iteration cancelled. need more data from sonar")
Logger.outdent() Logger.outDent()
Logger.log("============= FINISHING ITERATION $iterationCounter ============") Logger.log("============= FINISHING ITERATION $iterationCounter ============")
Logger.log("") Logger.log("")
} }
@@ -169,10 +115,10 @@ abstract class AbstractAlgorithm(val thisCar: Car) {
for ((index, dir) in res.directions.withIndex()) { for ((index, dir) in res.directions.withIndex()) {
res.directions[index] = when (dir) { res.directions[index] = when (dir) {
FORWARD -> BACKWARD FORWARD.id -> BACKWARD.id
BACKWARD -> FORWARD BACKWARD.id -> FORWARD.id
LEFT -> RIGHT LEFT.id -> RIGHT.id
RIGHT -> LEFT RIGHT.id -> LEFT.id
else -> throw IllegalArgumentException("Unexpected direction = $dir found during command inversion") else -> throw IllegalArgumentException("Unexpected direction = $dir found during command inversion")
} }
} }
@@ -186,8 +132,8 @@ abstract class AbstractAlgorithm(val thisCar: Car) {
Logger.indent() Logger.indent()
Logger.log("Last command: ${lastCommand.toString()}") Logger.log("Last command: ${lastCommand.toString()}")
Logger.log("Inverted cmd: ${invertedCommand.toString()}") Logger.log("Inverted cmd: ${invertedCommand.toString()}")
Logger.outdent() Logger.outDent()
moveCar(invertedCommand) carController.moveCar(invertedCommand)
} }
protected fun rollback(steps: Int) { protected fun rollback(steps: Int) {
@@ -199,7 +145,7 @@ abstract class AbstractAlgorithm(val thisCar: Car) {
rollback() rollback()
stepsRemaining-- stepsRemaining--
} }
Logger.outdent() Logger.outDent()
Logger.log("=== Finished rollback ===") Logger.log("=== Finished rollback ===")
} }
@@ -1,30 +1,29 @@
package algorithm package algorithm
class AlgorithmThread(val algorithmImpl: AbstractAlgorithm) : Thread() { class AlgorithmThread() : Thread() {
var algorithmImpl: AbstractAlgorithm? = null
private var count = 0 private var count = 0
override fun run() { override fun run() {
while (!algorithmImpl.isCompleted()) { val currentAlgorithm = algorithmImpl ?: return
while (!currentAlgorithm.isCompleted()) {
try { try {
if (count > 0) { if (count > 0) {
algorithmImpl.iterate() currentAlgorithm.iterate()
count-- count--
} else { } else {
Thread.sleep(1000) Thread.sleep(1000)
} }
} catch (e: InterruptedException) { } catch (e: InterruptedException) {
println("algorithm thread is interrupted")
break
} }
} }
println("algorithm is finished!") println("algorithm is completed")
} }
fun setCount(count: Int) { fun setCount(count: Int) {
this.count = count this.count = count
} }
}
fun cancel() {
count = 0
}
}
@@ -0,0 +1,60 @@
package algorithm
import CodedInputStream
import roomScanner.serialize
import RouteMetricRequest
import SonarRequest
import SonarResponse
import net.car.client.Client
import objects.CarConnection
import java.net.ConnectException
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeoutException
class CarController(val carConnection: CarConnection) {
fun scan(angles: IntArray, attempts: Int, windowSize: Int, smoothing: SonarRequest.Smoothing): IntArray {
val message = SonarRequest.BuilderSonarRequest(
angles = angles,
attempts = IntArray(angles.size, { attempts }),
smoothing = smoothing,
windowSize = windowSize)
.build()
val data = serialize(message.getSizeNoTag(), { message.writeTo(it) })
val response: ByteArray
try {
val future = carConnection.sendRequest(Client.Request.SONAR, data)
response = future.get(300, TimeUnit.SECONDS).responseBodyAsBytes
} catch (e: ConnectException) {
println("connection error!")
return IntArray(0)
} catch (e: TimeoutException) {
println("don't have response from net.car. Timeout!")
return IntArray(0)
}
return SonarResponse.BuilderSonarResponse(IntArray(0)).parseFrom(CodedInputStream(response)).build().distances
}
fun moveCar(message: RouteMetricRequest) {
val requestBytes = serialize(message.getSizeNoTag(), { message.writeTo(it) })
moveCar(requestBytes)
}
fun moveCar(distances: IntArray, directions: IntArray) {
val routeMetric = RouteMetricRequest.BuilderRouteMetricRequest(distances, directions).build()
moveCar(routeMetric)
}
private fun moveCar(messageBytes: ByteArray) {
try {
carConnection.sendRequest(Client.Request.ROUTE_METRIC, messageBytes).get(60, TimeUnit.SECONDS)
} catch (e: ConnectException) {
println("connection error!")
} catch (e: TimeoutException) {
println("don't have response from net.car. Timeout!")
}
return
}
}
@@ -6,13 +6,10 @@ import RouteMetricRequest
import SonarRequest import SonarRequest
import algorithm.geometry.* import algorithm.geometry.*
import objects.Car import objects.Car
import roomScanner.CarController.Direction.*
class RoomBypassingAlgorithm(thisCar: Car) : AbstractAlgorithm(thisCar) { class RoomBypassingAlgorithm(thisCar: Car) : AbstractAlgorithm(thisCar) {
//todo refactoring all algorithm package
override val ATTEMPTS: Int = 5 override val ATTEMPTS: Int = 5
override val SMOOTHING = SonarRequest.Smoothing.MEDIAN override val SMOOTHING = SonarRequest.Smoothing.MEDIAN
override val WINDOW_SIZE = 3 override val WINDOW_SIZE = 3
@@ -39,27 +36,23 @@ class RoomBypassingAlgorithm(thisCar: Car) : AbstractAlgorithm(thisCar) {
} }
private fun noOrthogonalMeasurementFound(anglesDistances: Map<Angle, AngleData>, state: CarState): RouteMetricRequest { private fun noOrthogonalMeasurementFound(anglesDistances: Map<Angle, AngleData>, state: CarState): RouteMetricRequest {
val resultBuilder = RouteMetricRequest.BuilderRouteMetricRequest(IntArray(0), IntArray(0))
resultBuilder.setDirections(getIntArray(FORWARD, RIGHT, FORWARD))
val wallAngle = calculateAngle(anglesDistances, state) val wallAngle = calculateAngle(anglesDistances, state)
Logger.indent() Logger.indent()
resultBuilder.setDistances(getIntArray(20, wallAngle.degs(), 75))
thisCar.angle = (RoomModel.walls.last().wallAngleOX.degs() - wallAngle.degs()).toDouble() thisCar.angle = (RoomModel.walls.last().wallAngleOX.degs() - wallAngle.degs()).toDouble()
addWall(-wallAngle) addWall(-wallAngle)
Logger.outdent() Logger.outDent()
calibrateAfterRotate = true calibrateAfterRotate = true
return resultBuilder.build() return buildRoute(
getIntArray(20, wallAngle.degs(), 75),
getIntArray(FORWARD.id, RIGHT.id, FORWARD.id))
} }
private fun wallAheadFound(anglesDistances: Map<Angle, AngleData>, state: CarState): RouteMetricRequest { private fun wallAheadFound(anglesDistances: Map<Angle, AngleData>, state: CarState): RouteMetricRequest {
val resultBuilder = RouteMetricRequest.BuilderRouteMetricRequest(IntArray(0), IntArray(0))
resultBuilder.setDirections(getIntArray(LEFT, FORWARD))
val wallAngle = calculateAngle(anglesDistances, state) val wallAngle = calculateAngle(anglesDistances, state)
resultBuilder.setDistances(getIntArray(wallAngle.degs(), 15))
thisCar.angle = (RoomModel.walls.last().wallAngleOX.degs() + wallAngle.degs()).toDouble() thisCar.angle = (RoomModel.walls.last().wallAngleOX.degs() + wallAngle.degs()).toDouble()
addWall(wallAngle) addWall(wallAngle)
calibrateAfterRotate = true calibrateAfterRotate = true
return resultBuilder.build() return buildRoute(getIntArray(wallAngle.degs(), 15), getIntArray(LEFT.id, FORWARD.id))
} }
private fun tryAlignParallelToWall(anglesDistances: Map<Angle, AngleData>, state: CarState, average: Double): RouteMetricRequest? { private fun tryAlignParallelToWall(anglesDistances: Map<Angle, AngleData>, state: CarState, average: Double): RouteMetricRequest? {
@@ -74,50 +67,41 @@ class RoomBypassingAlgorithm(thisCar: Car) : AbstractAlgorithm(thisCar) {
distRightBackward.distance < (average / 2) || distRightForward.distance < (average / 2)) { distRightBackward.distance < (average / 2) || distRightForward.distance < (average / 2)) {
continue continue
} }
if (Math.abs(distRightForward.distance - distRightBackward.distance) <= ISOSCALENESS_MIN_DIFF) { if (Math.abs(distRightForward.distance - distRightBackward.distance) <= ISOSCALENESS_MIN_DIFF) {
return null return null
} }
log("Flaw in align found, correcting") log("Flaw in align found, correcting")
val resultBuilder = RouteMetricRequest.BuilderRouteMetricRequest(IntArray(0), IntArray(0))
val rotationDirection = if (distRightBackward.distance > distRightForward.distance) LEFT else RIGHT val rotationDirection = if (distRightBackward.distance > distRightForward.distance) LEFT else RIGHT
resultBuilder.setDirections(getIntArray(rotationDirection)) return buildRoute(
resultBuilder.setDistances(getIntArray(Math.min(Math.abs(distRightBackward.distance - distRightForward.distance), 20))) getIntArray(Math.min(Math.abs(distRightBackward.distance - distRightForward.distance), 20)),
return resultBuilder.build() getIntArray(rotationDirection.id))
} }
return null // TODO: everything is broken, what to do? return null // TODO: everything is broken, what to do?
} }
private fun correctDistanceToParallelWall(anglesDistances: Map<Angle, AngleData>, state: CarState): RouteMetricRequest { private fun correctDistanceToParallelWall(anglesDistances: Map<Angle, AngleData>, state: CarState): RouteMetricRequest {
val resultBuilder = RouteMetricRequest.BuilderRouteMetricRequest(IntArray(0), IntArray(0))
val distToWall = anglesDistances[Angle(90)]!!.distance val distToWall = anglesDistances[Angle(90)]!!.distance
val rotationDirection = if (distToWall > DISTANCE_TO_WALL_UPPER_BOUND) RIGHT else LEFT val rotationDirection = if (distToWall > DISTANCE_TO_WALL_UPPER_BOUND) RIGHT else LEFT
val backRotationDirection = if (rotationDirection == RIGHT) LEFT else RIGHT val backRotationDirection = if (rotationDirection == RIGHT) LEFT else RIGHT
resultBuilder.setDirections(getIntArray(rotationDirection, FORWARD, backRotationDirection))
val rangeToCorridor = if (distToWall > DISTANCE_TO_WALL_UPPER_BOUND) { val rangeToCorridor = if (distToWall > DISTANCE_TO_WALL_UPPER_BOUND) {
distToWall - DISTANCE_TO_WALL_UPPER_BOUND distToWall - DISTANCE_TO_WALL_UPPER_BOUND
} else { } else {
DISTANCE_TO_WALL_LOWER_BOUND - distToWall DISTANCE_TO_WALL_LOWER_BOUND - distToWall
} }
resultBuilder.setDistances(getIntArray(2 * rangeToCorridor + 5, 20, (1.5 * rangeToCorridor).toInt())) return buildRoute(getIntArray(2 * rangeToCorridor + 5, 20, (1.5 * rangeToCorridor).toInt()),
return resultBuilder.build() getIntArray(rotationDirection.id, FORWARD.id, backRotationDirection.id))
} }
private fun moveForward(distToWall: Int): RouteMetricRequest { private fun moveForward(distToWall: Int): RouteMetricRequest {
val resultBuilder = RouteMetricRequest.BuilderRouteMetricRequest(IntArray(0), IntArray(0)) return buildRoute(getIntArray(Math.max(distToWall / 4, 20)), getIntArray(FORWARD.id))
resultBuilder.setDirections(getIntArray(FORWARD))
resultBuilder.setDistances(getIntArray(Math.max(distToWall / 4, 20)))
return resultBuilder.build()
} }
private fun addWall(angleWithPrevWall: Angle) { private fun addWall(angleWithPrevWall: Angle) {
log("Adding wall") log("Adding wall")
Logger.indent() Logger.indent()
updateWalls() updateWalls()
Logger.outdent() Logger.outDent()
val firstWall = RoomModel.walls.first() val firstWall = RoomModel.walls.first()
val lastWall = RoomModel.walls.last() val lastWall = RoomModel.walls.last()
if (circleFound) { if (circleFound) {
@@ -134,7 +118,7 @@ class RoomBypassingAlgorithm(thisCar: Car) : AbstractAlgorithm(thisCar) {
} }
} }
fun updateWalls() { private fun updateWalls() {
synchronized(RoomModel) { synchronized(RoomModel) {
val walls = RoomModel.walls val walls = RoomModel.walls
if (walls.size < 2) { if (walls.size < 2) {
@@ -166,7 +150,6 @@ class RoomBypassingAlgorithm(thisCar: Car) : AbstractAlgorithm(thisCar) {
val dist80 = anglesDistances[Angle(80)]!! val dist80 = anglesDistances[Angle(80)]!!
val dist90 = anglesDistances[Angle(90)]!! val dist90 = anglesDistances[Angle(90)]!!
val dist100 = anglesDistances[Angle(100)]!! val dist100 = anglesDistances[Angle(100)]!!
val dist110 = anglesDistances[Angle(110)]!!
val sonarAngle = (thisCar.angle - 90).toInt() val sonarAngle = (thisCar.angle - 90).toInt()
if (anglesDistances.filter { if (anglesDistances.filter {
@@ -191,7 +174,7 @@ class RoomBypassingAlgorithm(thisCar: Car) : AbstractAlgorithm(thisCar) {
log("Calibrating after rotate") log("Calibrating after rotate")
Logger.indent() Logger.indent()
val maybeAlignment = tryAlignParallelToWall(anglesDistances, state, average) val maybeAlignment = tryAlignParallelToWall(anglesDistances, state, average)
Logger.outdent() Logger.outDent()
if (maybeAlignment != null) { if (maybeAlignment != null) {
log("Realigning") log("Realigning")
return maybeAlignment return maybeAlignment
@@ -212,8 +195,8 @@ class RoomBypassingAlgorithm(thisCar: Car) : AbstractAlgorithm(thisCar) {
// Add point to room map // Add point to room map
val point = Point( val point = Point(
x = thisCar.x + dist90.distance * Math.cos(degreesToRadian(sonarAngle)), x = thisCar.x + dist90.distance * Math.cos(Angle(sonarAngle).rads()),
y = thisCar.y + dist90.distance * Math.sin(degreesToRadian(sonarAngle)) y = thisCar.y + dist90.distance * Math.sin(Angle(sonarAngle).rads())
) )
log("Adding middle point ${point.toString()} to wall ${RoomModel.walls.last().id}") log("Adding middle point ${point.toString()} to wall ${RoomModel.walls.last().id}")
RoomModel.walls.last().pushBackPoint(point) RoomModel.walls.last().pushBackPoint(point)
@@ -239,8 +222,8 @@ class RoomBypassingAlgorithm(thisCar: Car) : AbstractAlgorithm(thisCar) {
continue continue
} }
val point = Point( val point = Point(
x = thisCar.x + curDist * Math.cos(degreesToRadian((thisCar.angle - i).toInt())), x = thisCar.x + curDist * Math.cos(Angle((thisCar.angle - i).toInt()).rads()),
y = thisCar.y + curDist * Math.sin(degreesToRadian((thisCar.angle - i).toInt())) y = thisCar.y + curDist * Math.sin(Angle((thisCar.angle - i).toInt()).rads())
) )
log("Adding ${point.toString()} to wall ${RoomModel.walls.last().id}") log("Adding ${point.toString()} to wall ${RoomModel.walls.last().id}")
RoomModel.walls.last().pushBackPoint(point) RoomModel.walls.last().pushBackPoint(point)
@@ -251,7 +234,7 @@ class RoomBypassingAlgorithm(thisCar: Car) : AbstractAlgorithm(thisCar) {
log("4. Check if we have to align parallel to the wall") log("4. Check if we have to align parallel to the wall")
Logger.indent() Logger.indent()
val maybeAlignment = tryAlignParallelToWall(anglesDistances, state, average) val maybeAlignment = tryAlignParallelToWall(anglesDistances, state, average)
Logger.outdent() Logger.outDent()
if (maybeAlignment != null) { if (maybeAlignment != null) {
log("Realigning") log("Realigning")
return maybeAlignment return maybeAlignment
@@ -298,39 +281,21 @@ class RoomBypassingAlgorithm(thisCar: Car) : AbstractAlgorithm(thisCar) {
return args return args
} }
private fun buildRoute(distances: IntArray, directions: IntArray): RouteMetricRequest {
val resultBuilder = RouteMetricRequest.BuilderRouteMetricRequest(distances, directions)
return resultBuilder.build()
}
override fun isCompleted(): Boolean { override fun isCompleted(): Boolean {
return isCompleted return isCompleted
} }
override fun afterGetCommand(route: RouteMetricRequest) { override fun afterGetCommand(route: RouteMetricRequest) {
route.directions.forEachIndexed { idx, direction -> thisCar.refreshPositionAfterRoute(route)
when (direction) {
FORWARD -> {
thisCar.x += (Math.cos(degreesToRadian(thisCar.angle.toInt())) * route.distances[idx]).toInt()
thisCar.y += (Math.sin(degreesToRadian(thisCar.angle.toInt())) * route.distances[idx]).toInt()
}
BACKWARD -> {
thisCar.x -= (Math.cos(degreesToRadian(thisCar.angle.toInt())) * route.distances[idx]).toInt()
thisCar.y -= (Math.sin(degreesToRadian(thisCar.angle.toInt())) * route.distances[idx]).toInt()
}
LEFT -> {
route.distances[idx] = (CHARGE_CORRECTION * route.distances[idx]).toInt()
}
RIGHT -> {
route.distances[idx] = (CHARGE_CORRECTION * route.distances[idx]).toInt()
}
}
}
if (Math.round(Math.cos(Angle(thisCar.angle.toInt()).rads())).toInt() == 1 && thisCar.angle.toInt() != 0 if (Math.round(Math.cos(Angle(thisCar.angle.toInt()).rads())).toInt() == 1 && thisCar.angle.toInt() != 0
&& Vector(thisCar.x.toDouble(), thisCar.y.toDouble()).length() < RANGE_FROM_ZERO_POINT_TO_FINISH_ALG) { && Vector(thisCar.x.toDouble(), thisCar.y.toDouble()).length() < RANGE_FROM_ZERO_POINT_TO_FINISH_ALG) {
log("Found circle!") log("Found circle!")
circleFound = true circleFound = true
} }
} }
private fun degreesToRadian(angle: Int): Double {
return Math.PI * angle / 180
}
} }
@@ -3,7 +3,6 @@ package algorithm.geometry
class AngleData(val angle: Angle, val distance: Int) { class AngleData(val angle: Angle, val distance: Int) {
fun toPoint(carAngleOX: Angle): Point { fun toPoint(carAngleOX: Angle): Point {
//convert to global coordinate system //convert to global coordinate system
@@ -1,13 +1,15 @@
package algorithm.geometry package algorithm.geometry
private val eps = 0.1
fun Double.lt(other: Double): Boolean { fun Double.lt(other: Double): Boolean {
return this - other < -Util.eps return this - other < -eps
} }
fun Double.gt(other: Double): Boolean { fun Double.gt(other: Double): Boolean {
return this - other > Util.eps return this - other > eps
} }
fun Double.eq(other: Double): Boolean { fun Double.eq(other: Double): Boolean {
return Math.abs(this - other) < Util.eps return Math.abs(this - other) < eps
} }
@@ -1,7 +1,6 @@
package algorithm.geometry package algorithm.geometry
class Line(var A: Double, var B: Double, var C: Double) { class Line(var A: Double, var B: Double, var C: Double) {
val COMPARISON_THRESHOLD = 0
init { init {
normalize() normalize()
@@ -33,10 +32,8 @@ class Line(var A: Double, var B: Double, var C: Double) {
B *= -1 B *= -1
C *= -1 C *= -1
} }
} } else {
else if (A.lt(0.0)) {
{
if (A.lt(0.0)){
A *= -1 A *= -1
B *= -1 B *= -1
C *= -1 C *= -1
@@ -44,28 +41,8 @@ class Line(var A: Double, var B: Double, var C: Double) {
} }
} }
fun metricDist(other: Line): Double {
return Math.sqrt((A - other.A) * (A - other.A) + (B - other.B) * (B - other.B) + (C - other.C) * (C - other.C))
}
override fun equals(other: Any?): Boolean {
if (other == null) return false
if (other !is Line) return false
Logger.log("Comparing lines: ")
Logger.log(" this = ${this.toString()}")
Logger.log(" other = ${other.toString()}")
val dist = metricDist(other)
Logger.log(" Distance = ${dist}")
Logger.log(" COMPARISON_THRESHOLD = ${COMPARISON_THRESHOLD}")
return dist < COMPARISON_THRESHOLD
}
fun getDirectionVector(): Vector { fun getDirectionVector(): Vector {
return Vector (A, -B) return Vector(A, -B)
} }
} }
@@ -1,6 +0,0 @@
package algorithm.geometry
object Util {
val eps = 0.1
}
@@ -4,7 +4,7 @@ class Vector constructor(var x: Double, var y: Double) {
constructor(x1: Double, y1: Double, x2: Double, y2: Double) : this(x2 - x1, y2 - y1) constructor(x1: Double, y1: Double, x2: Double, y2: Double) : this(x2 - x1, y2 - y1)
constructor(begin: Point, end: Point) : this (begin.x, begin.y, end.x, end.y) constructor(begin: Point, end: Point) : this(begin.x, begin.y, end.x, end.y)
fun scalarProduct(vector: Vector): Double { fun scalarProduct(vector: Vector): Double {
return this.x * vector.x + this.y * vector.y return this.x * vector.x + this.y * vector.y
+15 -20
View File
@@ -1,5 +1,6 @@
package algorithm.geometry package algorithm.geometry
import Logger
import java.util.* import java.util.*
data class Wall(val wallAngleOX: Angle, data class Wall(val wallAngleOX: Angle,
@@ -18,7 +19,7 @@ data class Wall(val wallAngleOX: Angle,
} }
var isFinished = false var isFinished = false
val MAX_SLOPE = 0.2 private val MAX_SLOPE = 0.2
fun pushBackPoint(point: Point) { fun pushBackPoint(point: Point) {
Logger.log("Adding ${point.toString()}") Logger.log("Adding ${point.toString()}")
@@ -67,34 +68,34 @@ data class Wall(val wallAngleOX: Angle,
private fun approximatePointsByLine(): Line { private fun approximatePointsByLine(): Line {
var n = 0 var n = 0
var sumx = 0.0 var sumX = 0.0
var sumy = 0.0 var sumY = 0.0
var sumx2 = 0.0 var sumX2 = 0.0
for ((x2, y2) in rawPoints) { for ((x2, y2) in rawPoints) {
sumx += x2 sumX += x2
sumx2 += x2 * x2 sumX2 += x2 * x2
sumy += y2 sumY += y2
n++ n++
} }
val xbar = sumx / n val xBar = sumX / n
val ybar = sumy / n val yBar = sumY / n
// second pass: compute summary statistics // second pass: compute summary statistics
var xxbar = 0.0 var xxbar = 0.0
var yybar = 0.0 var yybar = 0.0
var xybar = 0.0 var xybar = 0.0
for ((x1, y1) in rawPoints) { for ((x1, y1) in rawPoints) {
xxbar += (x1 - xbar) * (x1 - xbar) xxbar += (x1 - xBar) * (x1 - xBar)
yybar += (y1 - ybar) * (y1 - ybar) yybar += (y1 - yBar) * (y1 - yBar)
xybar += (x1 - xbar) * (y1 - ybar) xybar += (x1 - xBar) * (y1 - yBar)
} }
var beta1 = xybar / xxbar var beta1 = xybar / xxbar
var beta0 = ybar - beta1 * xbar var beta0 = yBar - beta1 * xBar
if (Math.abs(beta1) > MAX_SLOPE) { if (Math.abs(beta1) > MAX_SLOPE) {
beta1 = xybar / yybar beta1 = xybar / yybar
beta0 = xbar - beta1 * ybar beta0 = xBar - beta1 * yBar
return Line(1.0, -beta1, -beta0) return Line(1.0, -beta1, -beta0)
} }
@@ -108,10 +109,4 @@ data class Wall(val wallAngleOX: Angle,
fun isHorizontal(): Boolean { fun isHorizontal(): Boolean {
return Math.abs(wallAngleOX.degs()) % 180 == 0 return Math.abs(wallAngleOX.degs()) % 180 == 0
} }
override fun equals(other: Any?): Boolean {
if (other == null) return false
if (other !is Wall) return false
return line.equals(other.line)
}
} }
@@ -0,0 +1,62 @@
package clInterface
import clInterface.executor.*
object DebugClInterface {
private val HELP_STRING = "available handlers:\n" +
"cars - get list of connected cars\n" +
"route [car_id] - setting a route for net.car with net.car id.\n" +
"sonar [car_id] - get sonar data\n" +
"dbinfo [car_id] [type] - refresh all net.car locations\n" +
"type is int value from: MEMORY_STATS - 0, SONAR_STATS - 1\n" +
"alg [count] - run algorithm. Make [count] iteration\n" +
"stop - exit from this interface and stop all threads\n"
private val algorithmExecutor = Algorithm()
private val executors = mapOf(
Pair("cars", CarsInformation()),
Pair("route", RouteMetric()),
Pair("sonar", Sonar()),
Pair("dbinfo", DebugInformation()),
Pair("alg", algorithmExecutor),
Pair("explore", Explore())
)
fun run() {
println(HELP_STRING)
while (true) {
val readString = readLine()
if (readString == null || readString.equals("stop")) {
algorithmExecutor.interruptAlgorithmThread()
break
}
if (readString.equals("")) {
continue
}
try {
executeCommand(readString)
} catch (exception: Exception) {
exception.printStackTrace()
println("Fail to execute command[$readString]: $exception")
println(HELP_STRING)
}
}
}
private fun printNotSupportedCommand(command: String) {
println("Incorrect command: $command")
println(HELP_STRING)
}
private fun executeCommand(readString: String) {
val command = readString.split(" ")[0].toLowerCase()
val executor = executors[command]
if (executor == null) {
printNotSupportedCommand(command)
return
}
executor.execute(readString)
}
}
@@ -0,0 +1,30 @@
package clInterface.executor
import algorithm.AlgorithmThread
import algorithm.RoomBypassingAlgorithm
import objects.Environment
class Algorithm : CommandExecutor {
private val algorithmThread = AlgorithmThread()
override fun execute(command: String) {
val params = command.split(" ")
val count =
if (params.size == 2) try {
params[1].toInt()
} catch (e: Exception) {
1
} else 1
if (algorithmThread.algorithmImpl == null) {
algorithmThread.algorithmImpl = RoomBypassingAlgorithm(Environment.map.values.last())
algorithmThread.start()
}
algorithmThread.setCount(count)
}
fun interruptAlgorithmThread() {
algorithmThread.setCount(0)
algorithmThread.interrupt()
}
}
@@ -0,0 +1,12 @@
package clInterface.executor
import objects.Environment
class CarsInformation : CommandExecutor {
override fun execute(command: String) {
synchronized(Environment, {
println(Environment.map.values)
})
}
}
@@ -0,0 +1,7 @@
package clInterface.executor
interface CommandExecutor {
fun execute(command:String)
}
@@ -0,0 +1,49 @@
package clInterface.executor
import CodedInputStream
import DebugRequest
import DebugResponseMemoryStats
import DebugResponseSonarStats
import roomScanner.serialize
import net.car.client.Client
import objects.Environment
import java.rmi.UnexpectedException
class DebugInformation : CommandExecutor {
override fun execute(command: String) {
val params = command.split(" ")
val car = Environment.map[params[1].toInt()]!!
val type = DebugRequest.Type.fromIntToType(params[2].toInt())
val request = DebugRequest.BuilderDebugRequest(type).build()
val requestType = when (type) {
DebugRequest.Type.MEMORY_STATS -> Client.Request.DEBUG_MEMORY
DebugRequest.Type.SONAR_STATS -> Client.Request.DEBUG_SONAR
else -> throw UnexpectedException(type.toString())
}
val responseData = car.carConnection.sendRequest(
requestType,
serialize(request.getSizeNoTag(), { request.writeTo(it) })
).get().responseBodyAsBytes
when (type) {
DebugRequest.Type.MEMORY_STATS -> {
val data = DebugResponseMemoryStats.BuilderDebugResponseMemoryStats(0, 0, 0, 0).parseFrom(CodedInputStream(responseData)).build()
println("Heap static tail: ${data.heapStaticTail}")
println("Heap dynamic tail: ${data.heapDynamicTail}")
println("Heap dynamic max size: ${data.heapDynamicMaxBytes}")
println("Heap dynamic total size: ${data.heapDynamicTotalBytes}")
}
DebugRequest.Type.SONAR_STATS -> {
val data = DebugResponseSonarStats.BuilderDebugResponseSonarStats(0, 0, 0, 0).parseFrom(CodedInputStream(responseData)).build()
println("Sonar measurement total: ${data.measurementCount}")
println("Failed check sums: ${data.measurementFailedChecksum}")
println("Failed command: ${data.measurementFailedCommand}")
println("Failed distance: ${data.measurementFailedDistance}")
}
else -> throw UnexpectedException(type.toString())
}
}
}
@@ -0,0 +1,28 @@
package clInterface.executor
import CodedInputStream
import roomScanner.serialize
import SonarExploreAngleRequest
import SonarExploreAngleResponse
import net.car.client.Client
import objects.Environment
class Explore : CommandExecutor {
override fun execute(command: String) {
val params = command.split(" ")
val car = Environment.map[params[1].toInt()]!!
val angle = params[2].toInt()
val window = params[3].toInt()
val request = SonarExploreAngleRequest.BuilderSonarExploreAngleRequest(angle, window).build()
val responseData = car.carConnection.sendRequest(
Client.Request.EXPLORE_ANGLE,
serialize(request.getSizeNoTag(), { request.writeTo(it) })
).get().responseBodyAsBytes
val distances = SonarExploreAngleResponse.BuilderSonarExploreAngleResponse(IntArray(0)).parseFrom(CodedInputStream(responseData)).build().distances
println("Received distances: [${distances.joinToString()}]")
}
}
@@ -0,0 +1,86 @@
package clInterface.executor
import CodedOutputStream
import RouteMetricRequest
import net.car.client.Client
import objects.Car
import objects.Environment
import java.net.ConnectException
class RouteMetric : CommandExecutor {
private val ROUTE_REGEX = Regex("route [0-9]{1,10}")
private val HELP_STRING = "print way points als [distance/degrees] [direction] in sm and degrees." +
"after enter all points print \"done\". for reset route print \"reset\". available directions:" +
"0 - FORWARD, 1 - BACKWARD, 2 - LEFT, 3 - RIGHT"
override fun execute(command: String) {
if (!ROUTE_REGEX.matches(command)) {
println("incorrect args of route command")
return
}
val id: Int
try {
id = command.split(" ")[1].toInt()
} catch (e: NumberFormatException) {
e.printStackTrace()
println("error in converting id to int type")
return
}
val car: Car? =
synchronized(Environment, {
Environment.map[id]
})
if (car == null) {
println("car with id=$id not found")
return
}
val routeMessage = getRouteMessage() ?: return
val requestBytes = ByteArray(routeMessage.getSizeNoTag())
routeMessage.writeTo(CodedOutputStream(requestBytes))
try {
car.carConnection.sendRequest(Client.Request.ROUTE_METRIC, requestBytes)
} catch (e: ConnectException) {
synchronized(Environment, {
Environment.map.remove(id)
})
}
}
private fun getRouteMessage(): RouteMetricRequest? {
println(HELP_STRING)
val distances = arrayListOf<Int>()
val directions = arrayListOf<Int>()
while (true) {
val readLine = readLine()!!.toLowerCase()
when (readLine) {
"reset" -> return null
"done" -> {
val routeBuilder = RouteMetricRequest.BuilderRouteMetricRequest(distances.toIntArray(), directions.toIntArray())
return routeBuilder.build()
}
}
val wayPointData = readLine.split(" ")
val distance: Int
val direction: Int
try {
distance = wayPointData[0].toInt()
direction = wayPointData[1].toInt()
} catch (e: NumberFormatException) {
println("error in converting distance or direction to int. try again")
continue
} catch (e: IndexOutOfBoundsException) {
println("format error, you must print two number separated by spaces. Try again")
continue
}
if (direction != 0 && direction != 1 && direction != 2 && direction != 3) {
println("direction $direction don't supported!")
println(HELP_STRING)
}
distances.add(distance)
directions.add(direction)
}
}
}
@@ -0,0 +1,72 @@
package clInterface.executor
import CodedOutputStream
import SonarRequest
import net.car.client.Client
import objects.Car
import objects.Environment
import java.net.ConnectException
class Sonar : CommandExecutor {
private val SONAR_REGEX = Regex("sonar [0-9]{1,10}")
override fun execute(command: String) {
if (!SONAR_REGEX.matches(command)) {
println("incorrect args of command sonar.")
return
}
val id: Int
try {
id = command.split(" ")[1].toInt()
} catch (e: NumberFormatException) {
e.printStackTrace()
println("error in converting id to int type")
return
}
val car: Car? = synchronized(Environment, {
Environment.map[id]
})
if (car == null) {
println("car with id=$id not found")
return
}
val requestMessage = getSonarRequest() ?: return
val requestBytes = ByteArray(requestMessage.getSizeNoTag())
requestMessage.writeTo(CodedOutputStream(requestBytes))
try {
car.carConnection.sendRequest(Client.Request.SONAR, requestBytes)
} catch (e: ConnectException) {
synchronized(Environment, {
Environment.map.remove(id)
})
}
}
private fun getSonarRequest(): SonarRequest? {
println("print angles, after printing all angles print done")
val angles = arrayListOf<Int>()
while (true) {
val command = readLine()!!.toLowerCase()
when (command) {
"reset" -> return null
"done" -> {
val sonarBuilder = SonarRequest.BuilderSonarRequest(angles.toIntArray(), IntArray(angles.size, { 5 }), 3, SonarRequest.Smoothing.MEDIAN)
return sonarBuilder.build()
}
else -> {
try {
val angle = command.toInt()
if (angle < 0 || angle > 180) {
println("incorrect angle $angle. angle must be in [0,180] and div on 4")
} else {
angles.add(angle)
}
} catch (e: NumberFormatException) {
println("error in converting angle to int. try again")
}
}
}
}
}
}
@@ -52,7 +52,6 @@ class ServerHandler(val handlers: Map<String, Handler>) : SimpleChannelInboundHa
} }
override fun exceptionCaught(ctx: ChannelHandlerContext?, cause: Throwable?) { override fun exceptionCaught(ctx: ChannelHandlerContext?, cause: Throwable?) {
println("exception")
cause?.printStackTrace() cause?.printStackTrace()
ctx?.close() ctx?.close()
} }
@@ -1,5 +1,6 @@
package net.web.server package net.web.server
import ModeChange
import io.netty.bootstrap.ServerBootstrap import io.netty.bootstrap.ServerBootstrap
import io.netty.channel.nio.NioEventLoopGroup import io.netty.channel.nio.NioEventLoopGroup
import io.netty.channel.socket.nio.NioServerSocketChannel import io.netty.channel.socket.nio.NioServerSocketChannel
@@ -1,11 +1,13 @@
package net.web.server.handlers package net.web.server.handlers
import net.web.server.Server
import java.util.*
import CodedInputStream import CodedInputStream
import CodedOutputStream import CodedOutputStream
import GenericResponse import GenericResponse
import ModeChange
import Result
import net.Handler import net.Handler
import net.web.server.Server
import java.util.*
class ChangeMode : Handler { class ChangeMode : Handler {
@@ -1,8 +1,10 @@
package net.web.server.handlers package net.web.server.handlers
import CodedOutputStream
import CodedInputStream import CodedInputStream
import CodedOutputStream
import DirectionRequest
import GenericResponse import GenericResponse
import Result
import net.Handler import net.Handler
import net.web.server.Server import net.web.server.Server
+28
View File
@@ -1,12 +1,40 @@
package objects package objects
import roomScanner.CarController.Direction
import RouteMetricRequest
import algorithm.geometry.Angle
class Car constructor(val uid: Int, host: String, port: Int) { class Car constructor(val uid: Int, host: String, port: Int) {
private val CHARGE_CORRECTION = 1.0//on full charge ok is 0.83 - 0.86
var x = 0.0 var x = 0.0
var y = 0.0 var y = 0.0
var angle = 0.0 var angle = 0.0
val carConnection = CarConnection(host, port) val carConnection = CarConnection(host, port)
fun refreshPositionAfterRoute(route:RouteMetricRequest) {
val carAngle = angle.toInt()
route.directions.forEachIndexed { idx, direction ->
when (direction) {
Direction.FORWARD.id -> {
x += (Math.cos(Angle(carAngle).rads()) * route.distances[idx]).toInt()
y += (Math.sin(Angle(carAngle).rads()) * route.distances[idx]).toInt()
}
Direction.BACKWARD.id -> {
x -= (Math.cos(Angle(carAngle).rads()) * route.distances[idx]).toInt()
y -= (Math.sin(Angle(carAngle).rads()) * route.distances[idx]).toInt()
}
Direction.LEFT.id -> {
route.distances[idx] = (CHARGE_CORRECTION * route.distances[idx]).toInt()
}
Direction.RIGHT.id -> {
route.distances[idx] = (CHARGE_CORRECTION * route.distances[idx]).toInt()
}
}
}
}
override fun toString(): String { override fun toString(): String {
return "$uid ; x:$x; y:$y; target:$angle" return "$uid ; x:$x; y:$y; target:$angle"
} }
@@ -4,7 +4,6 @@ import net.car.client.Client
import org.asynchttpclient.ListenableFuture import org.asynchttpclient.ListenableFuture
import org.asynchttpclient.Response import org.asynchttpclient.Response
class CarConnection(val host: String, val port: Int) { class CarConnection(val host: String, val port: Int) {
fun sendRequest(request: Client.Request, data: ByteArray): ListenableFuture<Response> { fun sendRequest(request: Client.Request, data: ByteArray): ListenableFuture<Response> {
return Client.makeRequest("http://$host:$port/${request.url}", data) return Client.makeRequest("http://$host:$port/${request.url}", data)
@@ -1,4 +1,4 @@
package RoomScanner package roomScanner
import CodedInputStream import CodedInputStream
import RouteMetricRequest import RouteMetricRequest
@@ -1,4 +1,4 @@
package RoomScanner package roomScanner
class RoomScanner(val controller: CarController) : Thread() { class RoomScanner(val controller: CarController) : Thread() {
private val points = mutableListOf<Pair<Double, Double>>() private val points = mutableListOf<Pair<Double, Double>>()
@@ -1,4 +1,4 @@
package RoomScanner package roomScanner
import CodedOutputStream import CodedOutputStream