algorithm refactoring
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
|
||||
import Exceptions.InactiveCarException
|
||||
import algorithm.AbstractAlgorithm
|
||||
import algorithm.RoomBypassingAlgorithm
|
||||
@@ -189,7 +188,7 @@ object DebugClInterface {
|
||||
when (command) {
|
||||
"reset" -> return null
|
||||
"done" -> {
|
||||
val sonarBuilder = SonarRequest.BuilderSonarRequest(angles.toIntArray())
|
||||
val sonarBuilder = SonarRequest.BuilderSonarRequest(angles.toIntArray(), IntArray(angles.size, {1}), 0, SonarRequest.Smoothing.NONE)
|
||||
return sonarBuilder.build()
|
||||
}
|
||||
else -> {
|
||||
|
||||
@@ -4,6 +4,7 @@ import CodedOutputStream
|
||||
import Exceptions.InactiveCarException
|
||||
import RouteMetricRequest
|
||||
import SonarRequest
|
||||
import algorithm.geometry.AngleData
|
||||
import io.netty.buffer.Unpooled
|
||||
import io.netty.handler.codec.http.*
|
||||
import objects.Car
|
||||
@@ -24,7 +25,7 @@ abstract class AbstractAlgorithm(val thisCar: Car, val exchanger: Exchanger<IntA
|
||||
|
||||
private var prevState: CarState? = null
|
||||
|
||||
private var prevSonarDistances = mapOf<Int, Double>()
|
||||
private var prevSonarDistances = mapOf<Int, AngleData>()
|
||||
private val defaultAngles = listOf(0, 60, 90, 120, 180).toIntArray()
|
||||
protected var requiredAngles = defaultAngles
|
||||
|
||||
@@ -34,43 +35,36 @@ abstract class AbstractAlgorithm(val thisCar: Car, val exchanger: Exchanger<IntA
|
||||
OUTER
|
||||
}
|
||||
|
||||
protected fun getData(angles: IntArray): DoubleArray {
|
||||
protected fun getData(angles: IntArray): IntArray {
|
||||
|
||||
val copyElemCount = 1
|
||||
val anglesCoped = IntArray(angles.size * copyElemCount, { angles[it / copyElemCount] })
|
||||
val attempts = 1
|
||||
val threshold = 0
|
||||
val smoothing = SonarRequest.Smoothing.NONE
|
||||
|
||||
val message = SonarRequest.BuilderSonarRequest(anglesCoped).build()
|
||||
val message = SonarRequest.BuilderSonarRequest(
|
||||
angles = angles,
|
||||
attempts = IntArray(angles.size, { attempts }),
|
||||
threshold = threshold,
|
||||
smoothing = smoothing)
|
||||
.build()
|
||||
val requestBytes = ByteArray(message.getSizeNoTag())
|
||||
message.writeTo(CodedOutputStream(requestBytes))
|
||||
val request = getDefaultHttpRequest(thisCar.host, sonarUrl, requestBytes)
|
||||
try {
|
||||
car.client.Client.sendRequest(request, thisCar.host, thisCar.port, mapOf(Pair("angles", anglesCoped)))
|
||||
car.client.Client.sendRequest(request, thisCar.host, thisCar.port, mapOf(Pair("angles", angles)))
|
||||
} catch (e: InactiveCarException) {
|
||||
println("connection error!")
|
||||
}
|
||||
|
||||
try {
|
||||
val distances = exchanger.exchange(IntArray(0), 300, TimeUnit.SECONDS)
|
||||
val result = DoubleArray(angles.size)
|
||||
for (i in 0..result.size - 1) {
|
||||
val distancesOnCurrentAngle = distances.drop(i * copyElemCount).take(copyElemCount)
|
||||
var sum = 0
|
||||
for (distance in distancesOnCurrentAngle) {
|
||||
if (distance != -1) {
|
||||
sum += distance
|
||||
}
|
||||
}
|
||||
if (sum != 0) {
|
||||
result[i] = (sum.toDouble()) / (copyElemCount)
|
||||
}
|
||||
}
|
||||
return result
|
||||
return distances
|
||||
} catch (e: InterruptedException) {
|
||||
println("don't have response from car!")
|
||||
} catch (e: TimeoutException) {
|
||||
println("don't have response from car. Timeout!")
|
||||
}
|
||||
return DoubleArray(0)
|
||||
return IntArray(0)
|
||||
}
|
||||
|
||||
protected fun moveCar(message: RouteMetricRequest) {
|
||||
@@ -103,12 +97,12 @@ abstract class AbstractAlgorithm(val thisCar: Car, val exchanger: Exchanger<IntA
|
||||
if (distances.size != angles.size) {
|
||||
throw RuntimeException("error! angles and distances have various sizes")
|
||||
}
|
||||
val anglesDistances = mutableMapOf<Int, Double>()
|
||||
val anglesDistances = mutableMapOf<Int, AngleData>()
|
||||
for (i in 0..angles.size - 1) {
|
||||
if (Math.abs(distances[i]) < 0.01) {
|
||||
continue
|
||||
}
|
||||
anglesDistances.put(angles[i], distances[i])
|
||||
anglesDistances.put(angles[i], AngleData(angles[i], distances[i]))
|
||||
}
|
||||
|
||||
this.requiredAngles = defaultAngles
|
||||
@@ -133,7 +127,7 @@ abstract class AbstractAlgorithm(val thisCar: Car, val exchanger: Exchanger<IntA
|
||||
return prevState
|
||||
}
|
||||
|
||||
protected fun getPrevSonarDistances(): Map<Int, Double> {
|
||||
protected fun getPrevSonarDistances(): Map<Int, AngleData> {
|
||||
return prevSonarDistances
|
||||
}
|
||||
|
||||
@@ -141,8 +135,8 @@ abstract class AbstractAlgorithm(val thisCar: Car, val exchanger: Exchanger<IntA
|
||||
return requiredAngles
|
||||
}
|
||||
|
||||
protected abstract fun getCarState(anglesDistances: Map<Int, Double>): CarState?
|
||||
protected abstract fun getCommand(anglesDistances: Map<Int, Double>, state: CarState): RouteMetricRequest
|
||||
protected abstract fun getCarState(anglesDistances: Map<Int, AngleData>): CarState?
|
||||
protected abstract fun getCommand(anglesDistances: Map<Int, AngleData>, state: CarState): RouteMetricRequest
|
||||
protected abstract fun afterGetCommand(route: RouteMetricRequest)
|
||||
|
||||
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
package algorithm
|
||||
|
||||
import algorithm.geometry.Line
|
||||
import algorithm.geometry.Vector
|
||||
import objects.Car
|
||||
import RouteMetricRequest
|
||||
import algorithm.geometry.*
|
||||
import java.util.concurrent.Exchanger
|
||||
|
||||
class RoomBypassingAlgorithm(thisCar: Car, exchanger: Exchanger<IntArray>) : AbstractAlgorithm(thisCar, exchanger) {
|
||||
|
||||
public var wallAngleWithOX = 0.0//in radian
|
||||
public var wallLength = 0.0//sm
|
||||
var wallAngleWithOX = 0.0//in radian
|
||||
var wallLength = 0.0//sm
|
||||
var errorCount = 0
|
||||
|
||||
var carX = 0
|
||||
@@ -18,17 +17,18 @@ class RoomBypassingAlgorithm(thisCar: Car, exchanger: Exchanger<IntArray>) : Abs
|
||||
|
||||
private var prevPoint = Pair(0.0, 0.0)
|
||||
|
||||
override fun getCarState(anglesDistances: Map<Int, Double>): CarState? {
|
||||
val dist0 = anglesDistances[0]
|
||||
val dist90 = anglesDistances[90]
|
||||
if (dist90 == null || dist90 > 85) {
|
||||
override fun getCarState(anglesDistances: Map<Int, AngleData>): CarState? {
|
||||
val angleData0 = anglesDistances[0]
|
||||
val angleData90 = anglesDistances[90]
|
||||
if (angleData90 == null || angleData90.distance > 85) {
|
||||
requiredAngles = getIntArray(0, 60, 90, 120, 180)
|
||||
return CarState.OUTER
|
||||
}
|
||||
val dist90 = angleData90.distance
|
||||
if (dist90 < 20) {
|
||||
return CarState.WALL
|
||||
}
|
||||
if (dist0 == null || dist0 > 70) {
|
||||
if (angleData0 == null || angleData0.distance > 70) {
|
||||
return CarState.WALL
|
||||
}
|
||||
return CarState.INNER
|
||||
@@ -59,14 +59,14 @@ class RoomBypassingAlgorithm(thisCar: Car, exchanger: Exchanger<IntArray>) : Abs
|
||||
}
|
||||
}
|
||||
|
||||
override fun getCommand(anglesDistances: Map<Int, Double>, state: CarState): RouteMetricRequest {
|
||||
val dist0 = anglesDistances[0]
|
||||
val dist60 = anglesDistances[60]
|
||||
val dist90 = anglesDistances[90]
|
||||
val dist120 = anglesDistances[120]
|
||||
val dist180 = anglesDistances[180]
|
||||
override fun getCommand(anglesDistances: Map<Int, AngleData>, state: CarState): RouteMetricRequest {
|
||||
val angleData0 = anglesDistances[0]
|
||||
val angleData60 = anglesDistances[60]
|
||||
val angleData90 = anglesDistances[90]
|
||||
val angleData120 = anglesDistances[120]
|
||||
val angleData180 = anglesDistances[180]
|
||||
val resultBuilder = RouteMetricRequest.BuilderRouteMetricRequest(IntArray(0), IntArray(0))
|
||||
if (dist120 == null || dist90 == null || dist60 == null) {
|
||||
if (angleData120 == null || angleData90 == null || angleData60 == null) {
|
||||
println("null distance!")
|
||||
if (errorCount >= 3) {
|
||||
errorCount = 0
|
||||
@@ -79,26 +79,26 @@ class RoomBypassingAlgorithm(thisCar: Car, exchanger: Exchanger<IntArray>) : Abs
|
||||
}
|
||||
if (getPrevState() == null) {
|
||||
//its first run, save right wall
|
||||
RoomModel.lines.add(Line(0.0, 1.0, dist90))
|
||||
prevPoint = Pair(0.0, -dist90)
|
||||
if (dist0 != null) {
|
||||
wallLength = dist0
|
||||
RoomModel.lines.add(Line(0.0, 1.0, angleData90.distance.toDouble()))
|
||||
prevPoint = Pair(0.0, -angleData90.distance.toDouble())
|
||||
if (angleData0 != null) {
|
||||
wallLength = angleData0.distance.toDouble()
|
||||
}
|
||||
}
|
||||
when (state) {
|
||||
CarState.WALL -> {
|
||||
if (wallLength.toInt() == 0 && (dist0 != null && dist180 != null)) {
|
||||
wallLength = dist0 + dist180
|
||||
if (wallLength.toInt() == 0 && (angleData0 != null && angleData180 != null)) {
|
||||
wallLength = angleData0.distance.toDouble() + angleData180.distance.toDouble()
|
||||
}
|
||||
if (dist90 > 40 || dist90 < 20) {
|
||||
val rotationDirection = if (dist90 > 40) RIGHT else LEFT
|
||||
if (angleData90.distance > 40 || angleData90.distance < 20) {
|
||||
val rotationDirection = if (angleData90.distance > 40) RIGHT else LEFT
|
||||
resultBuilder.setDirections(getIntArray(rotationDirection, FORWARD))
|
||||
resultBuilder.setDistances(getIntArray(10, 35))
|
||||
return resultBuilder.build()
|
||||
}
|
||||
|
||||
if (Math.abs(dist120 - dist60) > 10) {
|
||||
val rotationDirection = if (dist120 > dist60) LEFT else RIGHT
|
||||
if (Math.abs(angleData120.distance - angleData60.distance) > 10) {
|
||||
val rotationDirection = if (angleData120.distance > angleData60.distance) LEFT else RIGHT
|
||||
resultBuilder.setDirections(getIntArray(rotationDirection))
|
||||
resultBuilder.setDistances(getIntArray(15))
|
||||
return resultBuilder.build()
|
||||
@@ -111,18 +111,18 @@ class RoomBypassingAlgorithm(thisCar: Car, exchanger: Exchanger<IntArray>) : Abs
|
||||
CarState.INNER -> {
|
||||
|
||||
//в угле первое действие - встать максимально паралельно стене.
|
||||
if (Math.abs(dist120 - dist60) > 10) {
|
||||
val rotationDirection = if (dist120 > dist60) LEFT else RIGHT
|
||||
if (Math.abs(angleData120.distance - angleData60.distance) > 10) {
|
||||
val rotationDirection = if (angleData120.distance > angleData60.distance) LEFT else RIGHT
|
||||
resultBuilder.setDirections(getIntArray(rotationDirection))
|
||||
resultBuilder.setDistances(getIntArray(12))
|
||||
return resultBuilder.build()
|
||||
}
|
||||
|
||||
//если стоим паралельно - можно мерить угол
|
||||
val pointsNextLine = arrayListOf<Pair<Double, Double>>()
|
||||
for (angleDist in anglesDistances) {
|
||||
if (angleDist.key <= 15) {
|
||||
pointsNextLine.add(sonarAngleDistToPoint(angleDist.toPair()))
|
||||
val pointsNextLine = arrayListOf<Point>()
|
||||
for (angleData in anglesDistances.values) {
|
||||
if (angleData.angle <= 15) {
|
||||
pointsNextLine.add(angleData.toPoint(Util.radianToDegrees(wallAngleWithOX)))
|
||||
}
|
||||
}
|
||||
if (pointsNextLine.size < 3) {
|
||||
@@ -178,30 +178,22 @@ class RoomBypassingAlgorithm(thisCar: Car, exchanger: Exchanger<IntArray>) : Abs
|
||||
return angle * 180 / Math.PI
|
||||
}
|
||||
|
||||
private fun sonarAngleDistToPoint(angleDist: Pair<Int, Double>): Pair<Double, Double> {
|
||||
|
||||
val angle = wallAngleWithOX - degreesToRadian(angleDist.first)
|
||||
val dist = angleDist.second
|
||||
|
||||
val result = Pair(Math.cos(angle) * dist, Math.sin(angle) * dist)
|
||||
return result
|
||||
}
|
||||
|
||||
private fun approximatePointsByLine(points: Array<Pair<Double, Double>>): Line {
|
||||
private fun approximatePointsByLine(points: Array<Point>): Line {
|
||||
|
||||
// val p1 = points.first()
|
||||
// val p2 = points[1]
|
||||
// return Line(p2.second - p1.second, p1.first - p2.first, -p1.first * p2.second + p1.second * p2.first)
|
||||
|
||||
val sumX = points.sumByDouble { it.first }
|
||||
val sumXQuad = points.sumByDouble { it.first * it.first }
|
||||
val sumY = points.sumByDouble { it.second }
|
||||
val sumXY = points.sumByDouble { it.second * it.first }
|
||||
val sumX = points.sumByDouble { it.x }
|
||||
val sumXQuad = points.sumByDouble { it.x * it.x }
|
||||
val sumY = points.sumByDouble { it.y }
|
||||
val sumXY = points.sumByDouble { it.y * it.x }
|
||||
|
||||
val pointsCount = points.size
|
||||
val den = pointsCount * sumXQuad - sumX * sumX
|
||||
if (Math.abs(den) < 0.001) {
|
||||
return Line(1.0, 0.0, -points.first().first)
|
||||
return Line(1.0, 0.0, -points.first().x)
|
||||
}
|
||||
val k = (pointsCount * sumXY - sumX * sumY) / (pointsCount * sumXQuad - sumX * sumX)
|
||||
val b = (sumY - sumX * k) / pointsCount
|
||||
|
||||
@@ -35,23 +35,14 @@ object RoomModel {
|
||||
val end_y = IntArray(algorithm.points.size)
|
||||
|
||||
|
||||
for (i in 0..algorithm.points.size - 1) {
|
||||
for (i in 0..algorithm.points.size - 2) {
|
||||
val curPoint = algorithm.points[i]
|
||||
if (algorithm.points.size - 1 == i) {
|
||||
// val nextPoint = algorithm.points[0]
|
||||
// begin_x[i] = curPoint.first.toInt()
|
||||
// begin_y[i] = curPoint.second.toInt()
|
||||
//
|
||||
// end_x[i] = nextPoint.first.toInt()
|
||||
// end_y[i] = nextPoint.second.toInt()
|
||||
continue
|
||||
}
|
||||
val nextPoint = algorithm.points[i + 1]
|
||||
begin_x[i] = curPoint.first.toInt()
|
||||
begin_y[i] = curPoint.second.toInt()
|
||||
begin_x[i] = (curPoint.x + 0.5).toInt()
|
||||
begin_y[i] = (curPoint.y + 0.5).toInt()
|
||||
|
||||
end_x[i] = nextPoint.first.toInt()
|
||||
end_y[i] = nextPoint.second.toInt()
|
||||
end_x[i] = (nextPoint.x + 0.5).toInt()
|
||||
end_y[i] = (nextPoint.y + 0.5).toInt()
|
||||
}
|
||||
return Waypoints.BuilderWaypoints(begin_x, begin_y, end_x, end_y, false).build()
|
||||
}
|
||||
|
||||
@@ -3,20 +3,23 @@ package algorithm
|
||||
import objects.Car
|
||||
import java.util.concurrent.Exchanger
|
||||
import RouteMetricRequest
|
||||
import algorithm.geometry.AngleData
|
||||
import algorithm.geometry.Point
|
||||
|
||||
class RoomTest(thisCar: Car, exchanger: Exchanger<IntArray>) : AbstractAlgorithm(thisCar, exchanger) {
|
||||
|
||||
val points = arrayListOf<Pair<Double, Double>>()
|
||||
val points = arrayListOf<Point>()
|
||||
private val DISTANCE_TO_WALL_THRESHOLD = 60
|
||||
|
||||
var carX = 0
|
||||
var carY = 0
|
||||
var carAngle = 0
|
||||
|
||||
override fun getCarState(anglesDistances: Map<Int, Double>): CarState {
|
||||
override fun getCarState(anglesDistances: Map<Int, AngleData>): CarState {
|
||||
return CarState.WALL
|
||||
}
|
||||
|
||||
override fun getCommand(anglesDistances: Map<Int, Double>, state: CarState): RouteMetricRequest {
|
||||
override fun getCommand(anglesDistances: Map<Int, AngleData>, state: CarState): RouteMetricRequest {
|
||||
val dist0 = anglesDistances[0]
|
||||
val dist60 = anglesDistances[60]
|
||||
val dist90 = anglesDistances[90]
|
||||
@@ -28,27 +31,29 @@ class RoomTest(thisCar: Car, exchanger: Exchanger<IntArray>) : AbstractAlgorithm
|
||||
return resultBuilder.build()
|
||||
}
|
||||
val sonarAngle = carAngle - 90
|
||||
points.add(Pair(carX + dist90 * Math.cos(degreesToRadian(sonarAngle)),
|
||||
carY + dist90 * Math.sin(degreesToRadian(sonarAngle))))
|
||||
points.add(Point(
|
||||
x = carX + dist90.distance * Math.cos(degreesToRadian(sonarAngle)),
|
||||
y = carY + dist90.distance * Math.sin(degreesToRadian(sonarAngle))
|
||||
))
|
||||
if (dist120 == null || dist60 == null) {
|
||||
resultBuilder.setDirections(getIntArray(FORWARD))
|
||||
resultBuilder.setDistances(getIntArray(10))
|
||||
return resultBuilder.build()
|
||||
}
|
||||
if (dist0 != null && dist0 < 60) {
|
||||
if (dist0 != null && dist0.distance < DISTANCE_TO_WALL_THRESHOLD) {
|
||||
resultBuilder.setDirections(getIntArray(LEFT, FORWARD))
|
||||
resultBuilder.setDistances(getIntArray(20, 10))
|
||||
return resultBuilder.build()
|
||||
}
|
||||
val abs = Math.abs(dist120 - dist60)
|
||||
val abs = Math.abs(dist120.distance - dist60.distance)
|
||||
if (abs > 10) {
|
||||
val rotationDirection = if (dist120 > dist60) LEFT else RIGHT
|
||||
val rotationDirection = if (dist120.distance > dist60.distance) LEFT else RIGHT
|
||||
resultBuilder.setDirections(getIntArray(rotationDirection, FORWARD))
|
||||
resultBuilder.setDistances(getIntArray(10, 7))//todo calibrate
|
||||
return resultBuilder.build()
|
||||
}
|
||||
if (dist90 > 50 || dist90 < 25) {
|
||||
val rotationDirection = if (dist90 > 50) RIGHT else LEFT
|
||||
if (dist90.distance > 50 || dist90.distance < 25) {
|
||||
val rotationDirection = if (dist90.distance > 50) RIGHT else LEFT
|
||||
resultBuilder.setDirections(getIntArray(rotationDirection, FORWARD))
|
||||
resultBuilder.setDistances(getIntArray(10, 10))
|
||||
return resultBuilder.build()
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package algorithm.geometry
|
||||
|
||||
|
||||
class AngleData(val angle: Int, val distance: Int) {
|
||||
|
||||
|
||||
fun toPoint(carAngleOX: Int): Point {
|
||||
|
||||
//convert to global coordinate system
|
||||
val angle = carAngleOX - angle
|
||||
val radianAngle = Util.degreesToRadian(angle)
|
||||
|
||||
return Point(
|
||||
x = Math.cos(radianAngle) * distance,
|
||||
y = Math.sin(radianAngle) * distance
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package algorithm.geometry
|
||||
|
||||
class Point(val x: Double, val y: Double) {
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package algorithm.geometry
|
||||
|
||||
object Util {
|
||||
|
||||
|
||||
fun degreesToRadian(angleDegrees: Int): Double {
|
||||
return Math.PI * angleDegrees / 180.0
|
||||
}
|
||||
|
||||
fun radianToDegrees(angleRad: Double): Int {
|
||||
return (180.0 * angleRad / Math.PI).toInt()
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user