main server refactoring
This commit is contained in:
@@ -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")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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()
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
-1
@@ -1,4 +1,4 @@
|
|||||||
package RoomScanner
|
package roomScanner
|
||||||
|
|
||||||
import CodedInputStream
|
import CodedInputStream
|
||||||
import RouteMetricRequest
|
import RouteMetricRequest
|
||||||
+1
-1
@@ -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
-1
@@ -1,4 +1,4 @@
|
|||||||
package RoomScanner
|
package roomScanner
|
||||||
|
|
||||||
import CodedOutputStream
|
import CodedOutputStream
|
||||||
|
|
||||||
Reference in New Issue
Block a user