Browse Source

Upload files to ''

master
tsere 5 years ago
parent
commit
43d66e0a8b
  1. 489
      JsonSlowmotion.py
  2. 168
      arduino1.0.ino
  3. 278
      maze.adoc
  4. 298
      maze.py
  5. 10
      output.txt

489
JsonSlowmotion.py

@ -0,0 +1,489 @@
import json
class Node:
front = False
back = False
right = False
left = False
directions = {'south': {'Right': 'right', "Left": 'left', 'front': 'front', 'back': 'back'},
'north': {'Right': 'left', "Left": 'right', 'front': 'back', 'back': 'front'},
'west': {'Right': 'back', "Left": 'front', 'front': 'right', 'back': 'left'},
'east': {'Right': 'front', "Left": 'back', 'front': 'left', 'back': 'right'}}
# north
# west east
# south
# matches matrix walls to the ones that the car see: what wall in matrix is cars right wall
def makeNode(self):
a = self.directions[pos.direction]['back']
exec('self.' + a + "=True")
if m.frontDistance > pos.limit:
a = self.directions[pos.direction]['front']
exec('self.' + a + "=True")
if m.leftDistance > pos.limit:
a = self.directions[pos.direction]['Left']
exec('self.' + a + "=True")
if m.rightDistance > pos.limit:
a = self.directions[pos.direction]['Right']
exec('self.' + a + "=True")
print(pos.x, pos.y, self.right, self.front, self.left)
def getCarsRight(self):
a = self.directions[pos.direction]['Right']
ldic = locals()
exec('result=self.' + a, globals(), ldic)
result = ldic['result']
return result
# back
# right left
# front
# |_|
# gives a visual representation of the matrix
def __repr__(self):
x = ""
if self.right:
x = x + " "
else:
x = x + "|"
if self.front:
if self.back:
x = x + " "
else:
x = x + ""
else:
if self.back:
x = x + "__"
else:
x = x + ""
if self.left:
x = x + " "
else:
x = x + "|"
return x
class Possition:
x = 0
y = 0
limit = 29
oldFrontValue = 0 # !!!se allagh k sthn arxh
oldLeftValue=0
oldRightValue=0
counting = 15
movefinished = True
referencedistance = 0
prevNode = Node()
loopFlag = False
nodeChangedFlag=False
oldDirection = 'south'
direction = 'south'
directions = {'north': {'Right': 'east', "Left": 'west', 'Opposite': 'south'},
'south': {'Right': 'west', "Left": 'east', 'Opposite': 'north'},
'west': {'Right': 'north', "Left": 'south', 'Opposite': 'east'},
'east': {'Right': 'south', "Left": 'north', 'Opposite': 'west'}}
# |
# v
# north
# west east
# south
# changes the direction according to what direction it already was and which way it turned
def setDirection(self, movement):
self.direction = self.directions[self.direction][movement]
# changes the coordinates everytime a Node changes
def moveNode(self):
if self.direction == 'south':
self.y = self.y + 1
elif self.direction == 'north':
self.y = self.y - 1
elif self.direction == 'west':
self.x = self.x - 1
elif self.direction == 'east':
self.x = self.x + 1
# returns the front difference between two jsons
def findDifference(self):
difference = self.oldFrontValue - m.frontDistance
# if the node just got created or if it turned
if self.oldFrontValue is 0 or (self.oldDirection is not self.direction): difference = 0
print('dif', difference)
return difference
def howMuchMoved(self):
self.counting = self.counting + self.findDifference()
self.oldFrontValue = m.frontDistance
self.oldLeftValue = m.leftDistance
self.oldRightValue = m.rightDistance
print('has moved:', self.counting)
# we check if node changed then we change x,y , find out new walls/openings
def checkifNodeChanged(self):
self.nodeChangedFlag = False
if self.counting >= 30 :
flag = True
self.loopFlag = False
self.prevNode = maze[self.y][self.x]
self.moveNode()
maze[self.y][self.x].makeNode()
self.counting = 15
self.nodeChangedFlag=True
class Metrics:
rightDistance = 0
frontDistance = 0
leftDistance = 0
code = 0 # code0:forward() 1:turnR() 2:turnL() 3:turnAround() 3:break()
codedict = {"forward": 0, "turnR": 1, "turnL": 2, "turnAround": 3, "break": 4}
labelRD = "rightDistance"
labelFD = "frontDistance"
labelLD = "leftDistance"
def fromDict(self, d):
self.leftDistance = d[self.labelLD]
self.frontDistance = d[self.labelFD]
self.rightDistance = d[self.labelRD]
def toDict(self):
dict = {}
dict[self.labelRD] = self.rightDistance
dict[self.labelFD] = self.frontDistance
dict[self.labelLD] = self.leftDistance
return dict
def codeToDict(self):
dict = {}
dict["code"] = self.code
return dict
def toString(self):
return (self.labelRD + " " + str(self.rightDistance) + " " + self.labelFD + " " +
str(self.frontDistance) + " " + self.labelLD + " " + str(self.leftDistance))
def ignoreMetrics():
flag=False
if (abs(m.frontDistance-pos.oldFrontValue)>25):
flag=True
if (abs(m.leftDistance-pos.oldLeftValue)>25):
flag=True
if (abs(m.rightDistance-pos.oldRightValue)>25):
flag=True
return flag
def readJson(myjson):
x1 = myjson.split("{")
x2 = x1[1].split("}")
x = "{" + x2[0] + "}"
dict = json.loads(x)
m.fromDict(dict)
def createJson():
dict = m.codeToDict()
y = json.dumps(dict)
print(y)
return y
# north
# west east
# south
def checkforLoop():
flag = False
if pos.prevNode is not []:
if (pos.prevNode.getCarsRight() is False) and (maze[pos.y][pos.x].getCarsRight() is True):
print("loop")
flag = True
return flag
def moveFinished(lim=0):
flag = False
print(m.code)
# ean perpathse toul 25 ek diesxhse ena node
if m.code is m.codedict["forward"]:
if pos.nodeChangedFlag is True:
flag = True
# ean h palia de3ia timh plhsiazei to mprostino meros
if m.code is m.codedict["turnR"]:
if lim - m.frontDistance < 10:
flag = True
# ean h palia aristerh timh plhsiazei to mprostino meros
if m.code is m.codedict["turnL"]:
if lim - m.frontDistance < 10:
flag = True
# ean h de3ia plhsiazei thn palia aristerh timh
if m.code is m.codedict["turnAround"]:
if lim - m.rightDistance < 3:
flag = True
print('movedf', flag)
return flag
# movement logic: where to go changes direction if needs to and checks if node is changed
def move():
pos.howMuchMoved()
if pos.movefinished is True:
pos.oldDirection = pos.direction
if m.rightDistance > pos.limit:
pos.referencedistance = m.rightDistance
if pos.nodeChangedFlag is True:
#you just changed node so you must turn
if checkforLoop() is True:
m.code = m.codedict["turnR"]
pos.setDirection('Right')
else:
#you have already turned go ahead
m.code = m.codedict["forward"]
elif m.frontDistance > pos.limit:
m.code = m.codedict["forward"]
pos.movefinished = False
elif m.leftDistance > pos.limit:
pos.referencedistance = m.leftDistance
print('lim', pos.referencedistance)
m.code = m.codedict["turnL"]
pos.setDirection('Left')
pos.movefinished = False
else:
m.code = m.codedict["turnAround"]
pos.referencedistance = m.leftDistance
pos.setDirection('Opposite')
pos.movefinished = moveFinished(pos.referencedistance)
pos.checkifNodeChanged()
# elif (pos.loopFlag is True):
# m.code = m.codedict["forward"]
# elif(m.code is m.codedict['turnAround']):
# m.code = m.codedict["forward"]
print('direction:', pos.direction)
def main():
# read_serial = ["{\"frontDistance\":120,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":122,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":117,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":116,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":117,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":115,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":115,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":113,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":112,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":115,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":111,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":110,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":108,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":107,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":108,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":105,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":104,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":104,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":102,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":103,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":102,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":101,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":100,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":99,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":99,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":97,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":95,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":96,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":95,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":94,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":93,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":95,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":94,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":92,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":90,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":89,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":90,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":89,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":87,\"rightDistance\":4,\"leftDistance\":4}'"
# "{\"frontDistance\":86,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":85,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":85,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":83,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":82,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":81,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":80,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":75,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":78,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":74,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":72,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":70,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":65,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":64,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":60,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":57,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":54,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":52,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":50,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":52,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":52,\"rightDistance\":4,\"leftDistance\":42}'",
# "{\"frontDistance\":51,\"rightDistance\":4,\"leftDistance\":42}'",
# "{\"frontDistance\":4,\"rightDistance\":4,\"leftDistance\":42}'",
# ]
"""read_serial = ["{\"frontDistance\":70,\"rightDistance\":4,\"leftDistance\":70}'",
"{\"frontDistance\":65,\"rightDistance\":4,\"leftDistance\":70}'",
"{\"frontDistance\":60,\"rightDistance\":4,\"leftDistance\":70}'",
"{\"frontDistance\":55,\"rightDistance\":4,\"leftDistance\":70}'",
"{\"frontDistance\":45,\"rightDistance\":4,\"leftDistance\":70}'",
"{\"frontDistance\":40,\"rightDistance\":4,\"leftDistance\":4}'",
"{\"frontDistance\":10,\"rightDistance\":4,\"leftDistance\":45}'",
"{\"frontDistance\":35,\"rightDistance\":4,\"leftDistance\":45}'",
"{\"frontDistance\":5,\"rightDistance\":45,\"leftDistance\":4}'",
"{\"frontDistance\":34,\"rightDistance\":45,\"leftDistance\":4}'",
"{\"frontDistance\":4,\"rightDistance\":45,\"leftDistance\":4}'",
]"""
# read_serial = ["{\"frontDistance\":65,\"rightDistance\":4,\"leftDistance\":65}'",
# "{\"frontDistance\":35,\"rightDistance\":4,\"leftDistance\":4}'",
# "{\"frontDistance\":5,\"rightDistance\":4,\"leftDistance\":35}'"
# ]
'''read_serial = ["{\"frontDistance\":65,\"rightDistance\":5,\"leftDistance\":35}'",
"{\"frontDistance\":35,\"rightDistance\":5,\"leftDistance\":5}'",
"{\"frontDistance\":5,\"rightDistance\":5,\"leftDistance\":35}'",
"{\"frontDistance\":35,\"rightDistance\":5,\"leftDistance\":1000}'",
"{\"frontDistance\":5,\"rightDistance\":35,\"leftDistance\":5}'",
"{\"frontDistance\":35,\"rightDistance\":35,\"leftDistance\":5}'",
"{\"frontDistance\":5,\"rightDistance\":35,\"leftDistance\":5}'",
"{\"frontDistance\":35,\"rightDistance\":35,\"leftDistance\":5}'",
"{\"frontDistance\":5,\"rightDistance\":5,\"leftDistance\":35}'",
"{\"frontDistance\":35,\"rightDistance\":5,\"leftDistance\":35}'",
"{\"frontDistance\":5,\"rightDistance\":5,\"leftDistance\":35}'",
"{\"frontDistance\":125,\"rightDistance\":5,\"leftDistance\":35}'",
"{\"frontDistance\":95,\"rightDistance\":5,\"leftDistance\":5}'",
"{\"frontDistance\":65,\"rightDistance\":5,\"leftDistance\":5}'",
"{\"frontDistance\":35,\"rightDistance\":5,\"leftDistance\":125}'",
"{\"frontDistance\":5,\"rightDistance\":5,\"leftDistance\":5}'",
"{\"frontDistance\":125,\"rightDistance\":5,\"leftDistance\":5}'",
"{\"frontDistance\":95,\"rightDistance\":125,\"leftDistance\":5}'",
"{\"frontDistance\":125,\"rightDistance\":35,\"leftDistance\":95}'",
"{\"frontDistance\":95,\"rightDistance\":5,\"leftDistance\":125}'",
"{\"frontDistance\":65,\"rightDistance\":5,\"leftDistance\":5}'",
"{\"frontDistance\":35,\"rightDistance\":5,\"leftDistance\":5}'",
"{\"frontDistance\":5,\"rightDistance\":125,\"leftDistance\":5}'",
]'''
read_serial = [
"{\"frontDistance\":65,\"rightDistance\":5,\"leftDistance\":5}'",
"{\"frontDistance\":14000,\"rightDistance\":5,\"leftDistance\":5}'",
"{\"frontDistance\":45,\"rightDistance\":5,\"leftDistance\":5}'",
"{\"frontDistance\":25,\"rightDistance\":5,\"leftDistance\":5}'",
"{\"frontDistance\":15,\"rightDistance\":5,\"leftDistance\":5}'",
"{\"frontDistance\":5,\"rightDistance\":5,\"leftDistance\":5}'",
"{\"frontDistance\":30,\"rightDistance\":5,\"leftDistance\":5}'",
"{\"frontDistance\":28,\"rightDistance\":5,\"leftDistance\":5}'",
"{\"frontDistance\":25,\"rightDistance\":5,\"leftDistance\":95}'",
"{\"frontDistance\":20,\"rightDistance\":5,\"leftDistance\":95}'",
"{\"frontDistance\":16,\"rightDistance\":5,\"leftDistance\":95}'",
"{\"frontDistance\":10,\"rightDistance\":5,\"leftDistance\":95}'",
"{\"frontDistance\":8,\"rightDistance\":5,\"leftDistance\":95}'",
"{\"frontDistance\":5,\"rightDistance\":5,\"leftDistance\":95}'",
"{\"frontDistance\":10,\"rightDistance\":5,\"leftDistance\":85}'",
"{\"frontDistance\":20,\"rightDistance\":5,\"leftDistance\":75}'",
"{\"frontDistance\":25,\"rightDistance\":5,\"leftDistance\":85}'",
"{\"frontDistance\":35,\"rightDistance\":5,\"leftDistance\":90}'",
"{\"frontDistance\":45,\"rightDistance\":5,\"leftDistance\":105}'",
"{\"frontDistance\":65,\"rightDistance\":5,\"leftDistance\":105}'",
"{\"frontDistance\":80,\"rightDistance\":5,\"leftDistance\":105}'",
"{\"frontDistance\":95,\"rightDistance\":5,\"leftDistance\":1005}'",
"{\"frontDistance\":85,\"rightDistance\":5,\"leftDistance\":1005}'",
"{\"frontDistance\":75,\"rightDistance\":5,\"leftDistance\":5}'",
"{\"frontDistance\":60,\"rightDistance\":5,\"leftDistance\":5}'",
"{\"frontDistance\":65,\"rightDistance\":5,\"leftDistance\":5}'",
"{\"frontDistance\":55,\"rightDistance\":5,\"leftDistance\":5}'",
"{\"frontDistance\":45,\"rightDistance\":25,\"leftDistance\":25}'",
"{\"frontDistance\":25,\"rightDistance\":25,\"leftDistance\":25}'",
"{\"frontDistance\":35,\"rightDistance\":45,\"leftDistance\":35}'",
"{\"frontDistance\":35,\"rightDistance\":65,\"leftDistance\":35}'",
"{\"frontDistance\":5,\"rightDistance\":35,\"leftDistance\":5}'",
"{\"frontDistance\":35,\"rightDistance\":35,\"leftDistance\":5}'",
"{\"frontDistance\":5,\"rightDistance\":5,\"leftDistance\":35}'",
"{\"frontDistance\":35,\"rightDistance\":5,\"leftDistance\":5}'",
"{\"frontDistance\":5,\"rightDistance\":35,\"leftDistance\":5}'",
"{\"frontDistance\":35,\"rightDistance\":35,\"leftDistance\":5}'",
"{\"frontDistance\":5,\"rightDistance\":5,\"leftDistance\":35}'",
"{\"frontDistance\":7,\"rightDistance\":7,\"leftDistance\":28}'",
"{\"frontDistance\":9,\"rightDistance\":9,\"leftDistance\":20}'",
"{\"frontDistance\":12,\"rightDistance\":12,\"leftDistance\":25}'",
"{\"frontDistance\":25,\"rightDistance\":10,\"leftDistance\":30}'",
"{\"frontDistance\":29,\"rightDistance\":8,\"leftDistance\":33}'",
"{\"frontDistance\":32,\"rightDistance\":5,\"leftDistance\":35}'",
"{\"frontDistance\":35,\"rightDistance\":5,\"leftDistance\":5}'",
"{\"frontDistance\":5,\"rightDistance\":5,\"leftDistance\":35}'",
"{\"frontDistance\":65,\"rightDistance\":5,\"leftDistance\":35}'",
"{\"frontDistance\":35,\"rightDistance\":5,\"leftDistance\":5}'",
"{\"frontDistance\":5,\"rightDistance\":5,\"leftDistance\":35}'",
"{\"frontDistance\":35,\"rightDistance\":5,\"leftDistance\":65}'",
"{\"frontDistance\":5,\"rightDistance\":65,\"leftDistance\":5}'",
"{\"frontDistance\":65,\"rightDistance\":35,\"leftDistance\":5}'",
"{\"frontDistance\":35,\"rightDistance\":35,\"leftDistance\":65}'",
"{\"frontDistance\":35,\"rightDistance\":35,\"leftDistance\":65}'",
"{\"frontDistance\":5,\"rightDistance\":5,\"leftDistance\":5}'",
"{\"frontDistance\":95,\"rightDistance\":5,\"leftDistance\":5}'",
"{\"frontDistance\":65,\"rightDistance\":35,\"leftDistance\":35}'",
"{\"frontDistance\":35,\"rightDistance\":35,\"leftDistance\":35}'",
"{\"frontDistance\":5,\"rightDistance\":5,\"leftDistance\":5}'",
"{\"frontDistance\":65,\"rightDistance\":5,\"leftDistance\":5}'",
"{\"frontDistance\":35,\"rightDistance\":35,\"leftDistance\":35}'",
"{\"frontDistance\":35,\"rightDistance\":35,\"leftDistance\":35}'",
"{\"frontDistance\":5,\"rightDistance\":5,\"leftDistance\":5}'",
"{\"frontDistance\":65,\"rightDistance\":5,\"leftDistance\":5}'",
"{\"frontDistance\":35,\"rightDistance\":35,\"leftDistance\":35}'",
"{\"frontDistance\":35,\"rightDistance\":35,\"leftDistance\":35}'",
"{\"frontDistance\":5,\"rightDistance\":5,\"leftDistance\":35}'",
"{\"frontDistance\":35,\"rightDistance\":65,\"leftDistance\":5}'",
"{\"frontDistance\":65,\"rightDistance\":35,\"leftDistance\":5}'",
"{\"frontDistance\":35,\"rightDistance\":5,\"leftDistance\":5}'",
"{\"frontDistance\":5,\"rightDistance\":35,\"leftDistance\":5}'",
"{\"frontDistance\":35,\"rightDistance\":65,\"leftDistance\":5}'",
"{\"frontDistance\":5,\"rightDistance\":35,\"leftDistance\":5}'",
"{\"frontDistance\":35,\"rightDistance\":35,\"leftDistance\":5}'",
# "{\"frontDistance\":5,\"rightDistance\":5,\"leftDistance\":35}'",########
# "{\"frontDistance\":35,\"rightDistance\":5,\"leftDistance\":35}'",
# "{\"frontDistance\":5,\"rightDistance\":35,\"leftDistance\":5}'",
# "{\"frontDistance\":35,\"rightDistance\":35,\"leftDistance\":5}'",
# "{\"frontDistance\":5,\"rightDistance\":5,\"leftDistance\":35}'",
# "{\"frontDistance\":65,\"rightDistance\":5,\"leftDistance\":35}'",
# "{\"frontDistance\":35,\"rightDistance\":35,\"leftDistance\":65}'",
# "{\"frontDistance\":35,\"rightDistance\":35,\"leftDistance\":35}'",
# "{\"frontDistance\":5,\"rightDistance\":5,\"leftDistance\":35}'",
# "{\"frontDistance\":1005,\"rightDistance\":5,\"leftDistance\":95}'",
# "{\"frontDistance\":105,\"rightDistance\":5,\"leftDistance\":5}'",
]
readJson(read_serial[0])
maze[pos.x][pos.y].makeNode()
for i in read_serial:
readJson(i)
print(m.toString())
if (ignoreMetrics() is True):
print('ignore')
continue
move()
createJson()
print('#####################')
f = open('output.txt', 'w', encoding=('utf-8'))
for j in maze:
print(j)
f.write(str(j))
f.write('\n\n')
f.close()
############################################################################
m = Metrics()
pos = Possition()
h, l = 10, 5
maze = [[[] for x in range(h)] for y in range(l)]
for y in range(l):
for x in range(h):
maze[y][x] = Node()
main()

168
arduino1.0.ino

@ -0,0 +1,168 @@
#include <ArduinoJson.h>
class Metrics {
public:
//sensor readings
int rightDistance, leftDistance, frontDistance;
String labelRD = "rightDistance";
String labelLD = "leftDistance";
String labelFD = "frontDistance";
//method that returns the distances in a json format
String toString() {
return ("{\"" + labelRD + "\":\"" + rightDistance + "\",\"" + labelLD + "\":\"" + leftDistance + "\",\"" + labelFD + "\":\"" + frontDistance + "\"}");
};
};
// Input pins for motors. Side: Right/Left Cable Color: Red/Black
const int in_RR = 6 ;
const int in_RK = 9 ;
const int in_LR = 11 ;
const int in_LK = 10 ;
// define sensor pins t->trig e->echo
const int rightTPin = 2;
const int rightEPin = 3;
const int leftTPin = 7;
const int leftEPin = 8;
const int frontTPin = 4;
const int frontEPin = 5;
//define values for speed
const int high = 150;
const int low = 0;
const int capacity = 6 * JSON_OBJECT_SIZE(3);
Metrics *m = new Metrics();
//function to get input from a sensor
void getRightDistance() {
// Clears the trigPin
digitalWrite(rightTPin, LOW);
delayMicroseconds(2);
// Sets the trigPin on HIGH state for 10 micro seconds
digitalWrite(rightTPin, HIGH);
delayMicroseconds(10);
digitalWrite(rightTPin, LOW);
// Reads the echoPin, returns the sound wave travel time in microseconds
long duration = pulseIn(rightEPin, HIGH);
m->rightDistance = duration * 0.034 / 2;
}
void getLeftDistance() {
// Clears the trigPin
digitalWrite(leftTPin, LOW);
delayMicroseconds(2);
// Sets the trigPin on HIGH state for 10 micro seconds
digitalWrite(leftTPin, HIGH);
delayMicroseconds(10);
digitalWrite(leftTPin, LOW);
// Reads the echoPin, returns the sound wave travel time in microseconds
long duration = pulseIn(leftEPin, HIGH);
m->leftDistance = duration * 0.034 / 2;
}
void getFrontDistance() {
// Clears the trigPin
digitalWrite(frontTPin, LOW);
delayMicroseconds(2);
// Sets the trigPin on HIGH state for 10 micro seconds
digitalWrite(frontTPin, HIGH);
delayMicroseconds(10);
digitalWrite(frontTPin, LOW);
// Reads the echoPin, returns the sound wave travel time in microseconds
long duration = pulseIn(frontEPin, HIGH);
m->frontDistance = duration * 0.034 / 2;
}
//functions to control the car
void turnRight() {
analogWrite(in_RR, low);
analogWrite(in_RK, high);
analogWrite(in_LK, low);
analogWrite(in_LR, high);
}
void turnLeft() {
analogWrite(in_RR, high);
analogWrite(in_RK, low);
analogWrite(in_LK, high);
analogWrite(in_LR, low);
}
void forward() {
analogWrite(in_RR, high) ;
analogWrite(in_RK, low) ;
analogWrite(in_LR, high) ;
analogWrite(in_LK, low) ;
}
void brake() {
analogWrite(in_RR, low) ;
analogWrite(in_RK, low) ;
analogWrite(in_LR, low) ;
analogWrite(in_LK, low) ;
}
//function to receive command from raspberry pi
//command should be a string in json format {"code":"integer between 0-4"}
//code 0: forward
//code 1: turn right
//code 2: turn left
//code 3: turnAround !Need work
//code 4: brake
void getCommand() {
String input;
if (Serial.available() > 0) {
input = Serial.readString();
DynamicJsonDocument dict(capacity);
DeserializationError err = deserializeJson(dict, input);
int command = dict["code"].as<int>();
if (command == 0) {
forward();
}
else if (command == 1) {
turnRight();
}
else if (command == 2) {
turnLeft();
}
else if (command == 3) {
//turnAround();
}
else {
brake();
}
}
}
void setup() {
pinMode(in_RR, OUTPUT) ; //Logic pins are also set as output
pinMode(in_RK, OUTPUT) ;
pinMode(in_LR, OUTPUT) ;
pinMode(in_LK, OUTPUT) ;
pinMode(rightTPin, OUTPUT); // Sets the trigPin as an Output
pinMode(rightEPin, INPUT); // Sets the echoPin as an Input
pinMode(leftTPin, OUTPUT);
pinMode(leftEPin, INPUT);
pinMode(frontTPin, OUTPUT);
pinMode(frontEPin, INPUT);
Serial.begin(9600); // Starts the serial communication
}
void loop() {
getRightDistance();
getLeftDistance();
getFrontDistance();
Serial.println(m->toString());
getCommand();
}

278
maze.adoc

@ -0,0 +1,278 @@
Maze
===
Αγγελική <c151036@uniwa.gr>
Γιώργος <cs151056@uniwa.gr>
Χατζηλίας Κωνσταντίνος <cs151091@uniwa.gr>
:numbered:
== Περιγραφή του Project
Σκοπός του project είναι να δημιουργηθεί ένα αυτοκινητάκι το οποίο μπορεί αυτόνομα να μετακινηθεί
και να κάνει map έναν λαβύρινθο χρησιμοποιώντας χωρίς input απο κάποιον χρήστη,
χρησιμοποιώντας proximity sensors για να "βλέπει".
=== Υλικό που χρησιμοποιήθηκε
Για το project χρησιμοποιήθηκε ένα Arduino Uno και ένα Raspberry Pi.
=== Συνδεσμολογία
image:./images/car.jpg[
"car",width=256,
link="./images/car.jpg"]
Μπροστά βρίσκονται οι τρείς αισθητήρες που ελέγχουν την απόσταση μπροστά, δεξιά,αριστερά.
Βρίσκονται πάνω σε ένα Breadboard και παίρνουν ρεύμα κατευθείαν απο το arduino.
Στη μέση έχουμε το arduino στο οποίο συνδέονται όλα τα κομμάτια. Οι τροχοί τροφοδοτούνται απο τον κινητήρα(το κόκκινο) και ελέγχονται απο το arduino.
=== Κώδικας
.Κώδικας arduino
Το arduino είναι υπεύθυνο για να παίρνει το input απο τα sensors και να το στέλνει με κατάλληλη μορφή στο raspberry.
Αφού το κάνει αυτό περιμένει απο το raspberry να του στείλει οδηγίες για το πως να κινηθεί.
[source,arduino]
--
void loop() {
getRightDistance();
getLeftDistance();
getFrontDistance();
Serial.println(m->toString());
getCommand();
}
--
Τα inputs απο τα sensors αποθηκεύονται σε ένα αντικείμενο της κλάσης Metrics,
η οποία χειρίζεται και την μορφοποίηση των δεδομένων που θα σταλθούν στο raspberry σε μορφή json file.
[source,arduino]
--
class Metrics {
public:
//sensor readings
int rightDistance, leftDistance, frontDistance;
String labelRD = "rightDistance";
String labelLD = "leftDistance";
String labelFD = "frontDistance";
//method that returns the distances in a json format
String toString() {
return ("{\"" + labelRD + "\":\"" + rightDistance + "\",\"" + labelLD + "\":\"" + leftDistance + "\",\"" + labelFD + "\":\"" + frontDistance + "\"}");
};
};
--
Το getCommand function λαμβάνει ένα input απο το raspberry σε μορφή json και το μεταφράζει σε αντίστοιχη κίνηση για το αυτοκινητάκι.
[source,arduino]
--
//function to receive command from raspberry pi
//command should be a string in json format {"code":"integer between 0-4"}
//code 0: forward
//code 1: turn right
//code 2: turn left
//code 3: turnAround
//code 4: brake
void getCommand() {
String input;
if (Serial.available() > 0) {
input = Serial.readString();
DynamicJsonDocument dict(capacity);
DeserializationError err = deserializeJson(dict, input);
int command = dict["code"].as<int>();
if (command == 0) {
forward();
}
else if (command == 1) {
turnRight();
}
else if (command == 2) {
turnLeft();
}
else if (command == 3) {
//turnAround();
}
else {
brake();
}}}
--
=== Προβλήματα
Παρακάτω παρουσιάζονται κάποια προβλήματα.
==== Πρόβλημα με την τροφοδοσία
IMPORTANT: Λόγω αυτού το προβλήματος δεν μπορέσαμε να κάνουμε ελέγχους ούτε να το δοκιμάσουμε στον λαβύρινθο.
Όταν δεν υφίσταται τριβή στις ρόδες βλέπουμε πως κινούνται κανονικά και σύμφωνα με το input απο τα
sensors παίρνει τις ανάλογες αποφάσεις για το πως να κινηθεί. Όταν όμως βάζουμε το αυτοκινητάκι στο πάτωμα δυσκολεύεται να κινηθεί.
Αυτό οφείλεται στο γεγονός ότι δεν παρέχουμε αρκετή τροφοδοσία στους 4 κινητήρες για να μπορούν να τρέχουν στο πάτωμα.
CAUTION: Αυτό σημαίνει πως ότι test κάναμε, τα κάναμε δημιουργώντας input με το χέρι,
οπότε δεν είμαστε σίγουροι για την εγκυρότητα των αποτελεσμάτων.
==== Βασική ιδέα
Υπάρχει ένας κανόνας σύμφωνα με τον οποίο εαν ακολουθούμε συνεχόμενα και αδιαλείπτως τον δεξιό τοίχο τότε αδιαμφισβήτητα καταφέρνουμε να βγούμε από τον λαβύρινθο. Με αυτή την λογική εαν εντοπίσει κενό δεξιά του τότε στρίβει. Εαν δεν μπορεί να στρίψει δεξιά τότε πάει ευθεία. Εάν δεν μπορεί να κάνει τίποτε άλλο στρίβει αριστερά.
==== Επιστροφή προς τα πισω.
Χρησιμοποιώντας τον παραπάνω κανόνα του δεξιού χεριού, όταν το αυτοκινητάκι μπορεί να επιλέξει ανάμεσα στο να προχωρήσει ευθεία ή να στρίψει,
επιλέγει πάντα να στρίβει δεξιά. Αυτό δημιουργεί πρόβλημα καθώς το όχημα στρίβει σε μορφη tank, δηλαδή χρειάζεται δύο κινήσεις για να στρίψει.
Εφόσον κάνει την στροφή βλέπει πως έχει ακόμα να επιλέξει ανάμεσα στο να πάει ευθεία ή να στρίψει,
και καταλήγει να στρίβει προς τα εκεί που ήρθε.
Αυτο το πρόβλημα είναι ανεξάρτητο από την υλοποίηση δηλαδή θα εμφανιζόταν εάν είχαμε γραφο.
image:./images/return.png[
"car",width=256,
link="./images/return.png"]
==== Διαστάσεις του χάρτη
Έχουμε κάνει κάποιες παραδοχές όπως ότι ο χάρτης αποτελείται απο blocks 30x30cm,
και τον υλοποιήσαμε ως έναν πίνακα μεγέθους 5x10.
Επίσης θεωρούμε πως το αυτοκινητάκι ξεκινάει απο το πάνω αριστερά μέρος στον χάρτη.
CAUTION: Μπορεί να διορθωθεί εαν κάθε φορά που εντοπίζει άνοιγμα εκτός του υπάρχων χάρτη θα δημιουργεί αντιστοίχως μια καινούργια γραμμή ή μια στήλη και διαμορφώνοντας τα αντίστοιχα χ,y.
==== Αντίληψη κίνησης
Ενα ακόμη πρόβλημα που αντιμετωπίσαμε ήταν το να ξέρουμε κάθε πότε ολοκλήρωσε μια κίνηση.
Δηλαδή ότι πραγματοποιήθηκε μια στροφή ή ότι ολοκλήρωσε μια αναστροφή χωρίς να ξέρουμε τον χρόνο που χρειάζεται για να στριψει.
Αυτό που σκεφτήκαμε είναι για το μπροστά αρκεί να έχει διανύσει 30 εκατοστά(δηλαδή να έχει αλάξει ένα node),
για την δεξιά στροφή πρέπει καθώς γυρίζει η μπροστινή τιμή να πλησιάσει την παλιά δεξιά, ανάλογα για το αριστερά. Τέλος στην αναστροφή πρέπει καθώς γυρίζει το δεξί μέρος να πάρει την τιμή του παλιού αριστερού.
.Κώδικας raspberry
[source,python]
--
def moveFinished(lim=0):
flag = False
print(m.code)
# ean perpathse toul 25 ek diesxhse ena node
if m.code is m.codedict["forward"]:
if pos.nodeChangedFlag is True:
flag = True
# ean h palia de3ia timh plhsiazei to mprostino meros
if m.code is m.codedict["turnR"]:
if lim - m.frontDistance < 10:
flag = True
# ean h palia aristerh timh plhsiazei to mprostino meros
if m.code is m.codedict["turnL"]:
if lim - m.frontDistance < 10:
flag = True
# ean h de3ia plhsiazei thn palia aristerh timh
if m.code is m.codedict["turnAround"]:
if lim - m.rightDistance < 3:
flag = True
print('movedf', flag)
return flag
--
==== Λανθασμένες ακραίες τιμές
Στις δοκιμές που κάναμε είδαμε επίσης πως στην αρχή και σε άκυρες στιγμές οι αισθητήρες δίνουν ακραία νούμερα
με αποτέλεσμα να νομίζει το πρόγραμμα ότι βλέπει άνοιγμα. Για να το αντιμετωπίσουμε ελέγχουμε εάν οι διαφορά από το προηγούμενο Node είναι πολύ μεγάλη ώστε να την αγνοήσουμε.
.Κώδικας raspberry
[source,python]
--
if (abs(m.frontDistance-prevNode.frontDistance)>25):
continue
if (abs(m.leftDistance-prevNode.leftDistance)>25):
continue
if (abs(m.rightDistance-prevNode.rightDistance)>25):
continue
--
==== Αποθήκευση σε αρχείο
Όταν ανανεώνουμε τον λαβύρινθο ανανεώνεται και το αρχείο που τον αποθηκεύουμε
.Κώδικας raspberry
[source,python]
--
f = open('output.txt', 'w', encoding=('utf-8'))
for j in maze:
print(j)
f.write(str(j))
f.write('\n\n')
f.close()
--
==== Μετακίνηση
.Κώδικας raspberry
[source,python]
--
# movement logic: where to go changes direction if needs to and checks if node is changed
def move():
pos.howMuchMoved()
if pos.movefinished is True:
pos.oldDirection = pos.direction
if m.rightDistance > pos.limit:
pos.referencedistance = m.rightDistance
if pos.nodeChangedFlag is True:
#you just changed node so you must turn
if checkforLoop() is True:
m.code = m.codedict["turnR"]
pos.setDirection('Right')
else:
#you have already turned go ahead
m.code = m.codedict["forward"]
elif m.frontDistance > pos.limit:
m.code = m.codedict["forward"]
pos.movefinished = False
elif m.leftDistance > pos.limit:
pos.referencedistance = m.leftDistance
print('lim', pos.referencedistance)
m.code = m.codedict["turnL"]
pos.setDirection('Left')
pos.movefinished = False
else:
m.code = m.codedict["turnAround"]
pos.referencedistance = m.leftDistance
pos.setDirection('Opposite')
pos.movefinished = moveFinished(pos.referencedistance)
pos.checkifNodeChanged()
def move():
nodeChanged=pos.checkifNodeChanged() ######isws n prepei na elegxei gia olh thn kinhsh to oldDirection
if nodeChanged is True:
if m.rightDistance > pos.limit:
if checkforLoop() is True:
pos.loopFlag= True
m.code = m.codedict["turnR"]
pos.setDirection('Right')
elif m.frontDistance > pos.limit:
m.code = m.codedict["forward"]
elif m.leftDistance > pos.limit:
m.code = m.codedict["turnL"]
pos.setDirection('Left')
else:
m.code = m.codedict["turnAround"]
pos.setDirection('Opposite')
elif (pos.loopFlag is True):
m.code = m.codedict["forward"]
elif(m.code is m.codedict['turnAround']):
m.code = m.codedict["forward"]
--

298
maze.py

@ -0,0 +1,298 @@
import serial
import json
ser = serial.Serial('/dev/ttyACM0',9600)
class Possition:
x = 0
y = 0
limit = 25
class Node:
front = False
right = False
left = False
back = False
directions = {'south': {'Right': 'right', "Left": 'left', 'front': 'front', 'back': 'back'},
'north': {'Right': 'left', "Left": 'right', 'front': 'back', 'back': 'front'},
'west': {'Right': 'back', "Left": 'front', 'front': 'right', 'back': 'left'},
'east': {'Right': 'front', "Left": 'back', 'front': 'left', 'back': 'right'}}
# north
# west east
# south
# matches matrix walls to the ones that the car see: what wall in matrix is cars right wall
def makeNode(self):
a = self.directions[pos.direction]['back']
exec('self.' + a + "=True")
if m.frontDistance > pos.limit:
a = self.directions[pos.direction]['front']
exec('self.' + a + "=True")
if m.leftDistance > pos.limit:
a = self.directions[pos.direction]['Left']
exec('self.' + a + "=True")
if m.rightDistance > pos.limit:
a = self.directions[pos.direction]['Right']
exec('self.' + a + "=True")
print(pos.x, pos.y, self.right, self.front, self.left)
def getCarsRight(self):
a = self.directions[pos.direction]['Right']
ldic = locals()
exec('result=self.' + a, globals(), ldic)
result = ldic['result']
return result
# back
# right left
# front
# |_|
# gives a visual representation of the matrix
def __repr__(self):
x = ""
if self.right:
x = x + " "
else:
x = x + "|"
if self.front:
if self.back:
x = x + " "
else:
x = x + ""
else:
if self.back:
x = x + "__"
else:
x = x + ""
if self.left:
x = x + " "
else:
x = x + "|"
return x
class Possition:
x = 0
y = 0
limit = 29
oldFrontValue = 0 # !!!se allagh k sthn arxh
oldLeftValue=0
oldRightValue=0
counting = 15
movefinished = True
referencedistance = 0
prevNode = Node()
loopFlag = False
nodeChangedFlag=False
oldDirection = 'south'
direction = 'south'
directions = {'north': {'Right': 'east', "Left": 'west', 'Opposite': 'south'},
'south': {'Right': 'west', "Left": 'east', 'Opposite': 'north'},
'west': {'Right': 'north', "Left": 'south', 'Opposite': 'east'},
'east': {'Right': 'south', "Left": 'north', 'Opposite': 'west'}}
# |
# v
# north
# west east
# south
# changes the direction according to what direction it already was and which way it turned
def setDirection(self, movement):
self.direction = self.directions[self.direction][movement]
# changes the coordinates everytime a Node changes
def moveNode(self):
if self.direction == 'south':
self.y = self.y + 1
elif self.direction == 'north':
self.y = self.y - 1
elif self.direction == 'west':
self.x = self.x - 1
elif self.direction == 'east':
self.x = self.x + 1
# returns the front difference between two jsons
def findDifference(self):
difference = self.oldFrontValue - m.frontDistance
# if the node just got created or if it turned
if self.oldFrontValue is 0 or (self.oldDirection is not self.direction): difference = 0
print('dif', difference)
return difference
def howMuchMoved(self):
self.counting = self.counting + self.findDifference()
self.oldFrontValue = m.frontDistance
self.oldLeftValue = m.leftDistance
self.oldRightValue = m.rightDistance
print('has moved:', self.counting)
# we check if node changed then we change x,y , find out new walls/openings
def checkifNodeChanged(self):
self.nodeChangedFlag = False
if self.counting >= 30 :
flag = True
self.loopFlag = False
self.prevNode = maze[self.y][self.x]
self.moveNode()
maze[self.y][self.x].makeNode()
self.counting = 15
self.nodeChangedFlag=True
class Metrics:
rightDistance = 0
frontDistance = 0
leftDistance = 0
code = 0 # code0:forward() 1:turnR() 2:turnL() 3:turnAround() 3:break()
codedict = {"forward": 0, "turnR": 1, "turnL": 2, "turnAround": 3, "break": 4}
labelRD = "rightDistance"
labelFD = "frontDistance"
labelLD = "leftDistance"
def fromDict(self, d):
self.leftDistance = d[self.labelLD]
self.frontDistance = d[self.labelFD]
self.rightDistance = d[self.labelRD]
def toDict(self):
dict = {}
dict[self.labelRD] = self.rightDistance
dict[self.labelFD] = self.frontDistance
dict[self.labelLD] = self.leftDistance
return dict
def codeToDict(self):
dict = {}
dict["code"] = self.code
return dict
def toString(self):
return (self.labelRD + " " + str(self.rightDistance) + " " + self.labelFD + " " +
str(self.frontDistance) + " " + self.labelLD + " " + str(self.leftDistance))
def readJson(myjson):
x1=myjson.split('{')
x2=x1[1].split('}')
x="{"+x2[0]+"}"
dict = json.loads(x)
m.fromDict(dict)
def createJson():
dict = m.codeToDict()
y = json.dumps(dict)
return y
def ignoreMetrics():
flag=False
if (abs(m.frontDistance-pos.oldFrontValue)>25):
flag=True
if (abs(m.leftDistance-pos.oldLeftValue)>25):
flag=True
if (abs(m.rightDistance-pos.oldRightValue)>25):
flag=True
return flag
# north
# west east
# south
def checkforLoop():
flag = False
if pos.prevNode is not []:
if (pos.prevNode.getCarsRight() is False) and (maze[pos.y][pos.x].getCarsRight() is True):
print("loop")
flag = True
return flag
def moveFinished(lim=0):
flag = False
print(m.code)
# ean perpathse toul 25 ek diesxhse ena node
if m.code is m.codedict["forward"]:
if pos.nodeChangedFlag is True:
flag = True
# ean h palia de3ia timh plhsiazei to mprostino meros
if m.code is m.codedict["turnR"]:
if lim - m.frontDistance < 10:
flag = True
# ean h palia aristerh timh plhsiazei to mprostino meros
if m.code is m.codedict["turnL"]:
if lim - m.frontDistance < 10:
flag = True
# ean h de3ia plhsiazei thn palia aristerh timh
if m.code is m.codedict["turnAround"]:
if lim - m.rightDistance < 3:
flag = True
print('movedf', flag)
return flag
# movement logic: where to go changes direction if needs to and checks if node is changed
def move():
pos.howMuchMoved()
if pos.movefinished is True:
pos.oldDirection = pos.direction
if m.rightDistance > pos.limit:
pos.referencedistance = m.rightDistance
if pos.nodeChangedFlag is True:
#you just changed node so you must turn
if checkforLoop() is True:
m.code = m.codedict["turnR"]
pos.setDirection('Right')
else:
#you have already turned go ahead
m.code = m.codedict["forward"]
elif m.frontDistance > pos.limit:
m.code = m.codedict["forward"]
pos.movefinished = False
elif m.leftDistance > pos.limit:
pos.referencedistance = m.leftDistance
print('lim', pos.referencedistance)
m.code = m.codedict["turnL"]
pos.setDirection('Left')
pos.movefinished = False
else:
m.code = m.codedict["turnAround"]
pos.referencedistance = m.leftDistance
pos.setDirection('Opposite')
pos.movefinished = moveFinished(pos.referencedistance)
pos.checkifNodeChanged()
m=Metrics()
pos = Possition()
h, l = 10, 5
maze = [[[] for x in range(h)] for y in range(l)]
for y in range(l):
for x in range(h):
maze[y][x]=Node()
while True:
try:
ser.flush()
read_serial=ser.readline()
ser.write("a".encode())
print("print",read_serial)
read_serial = read_serial.decode('utf-8')
readJson(read_serial)
if (ignoreMetrics() is True):
print('ignore')
continue
move()
y=createJson()
ser.write(str(y).encode())
f = open('output.txt', 'w', encoding=('utf-8'))
for j in maze:
print(j)
f.write(str(j))
f.write('\n\n')
f.close()
except:
pass

10
output.txt

@ -0,0 +1,10 @@
[| |, |二|, |二|, |二|, |二|, |二|, |二|, |二|, |二|, |二|]
[|二|, |二|, |二|, |二|, |二|, |二|, |二|, |二|, |二|, |二|]
[|二|, |二|, |二|, |二|, |二|, |二|, |二|, |二|, |二|, |二|]
[|二|, |二|, |二|, |二|, |二|, |二|, |二|, |二|, |二|, |二|]
[|二|, |二|, |二|, |二|, |二|, |二|, |二|, |二|, |二|, |二|]
Loading…
Cancel
Save