Skip to content

Commit

Permalink
Edge detection (#57)
Browse files Browse the repository at this point in the history
* skip waiting line

* support 3 or more edges per line

* change log format

* show z instead of sensor output

* remove duplicates

* check feedrate diff

* add not in range sensor output

* refactor sensor_data_count_and_distance_when_measuring

* fix getting line length

* import pair length when model imported

* add offset to arc center

* import production data

* add new model

* fix fetch results for tracing

* estimate data with production data
  • Loading branch information
yuichiroaoki authored Dec 18, 2023
1 parent 81c4186 commit 6d2cfcc
Show file tree
Hide file tree
Showing 26 changed files with 1,229 additions and 174 deletions.
1 change: 1 addition & 0 deletions server/data/config/dev.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ sensor:
middle_output: 9400
response_time: 15.0 # ms
tolerance: 0.6
not_in_range_output: 18800
trace:
min_measure_count: 5
max_feedrate: 2500 # mm/min
Expand Down
1 change: 1 addition & 0 deletions server/data/config/production.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ sensor:
middle_output: 9400
response_time: 10.0 # ms
tolerance: 0.6
not_in_range_output: 18800
trace:
min_measure_count: 10
max_feedrate: 2500 # mm/min
Expand Down
2 changes: 1 addition & 1 deletion server/server/listener/hakaru.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import logging
from server.measure.sensor import mm_to_sensor_output_diff

logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s:%(message)s")
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s: %(message)s")
logger = logging.getLogger(__name__)

sensor_online = False
Expand Down
2 changes: 1 addition & 1 deletion server/server/listener/listener.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from .mtmqtt import listen_data_with_mqtt
import logging

logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s:%(message)s")
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s: %(message)s")
logger = logging.getLogger(__name__)


Expand Down
2 changes: 1 addition & 1 deletion server/server/listener/mt/reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
import paho.mqtt.client as mqtt
from .parse import mtconnect_table_row_data

logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s:%(message)s")
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s: %(message)s")
logger = logging.getLogger(__name__)


Expand Down
9 changes: 6 additions & 3 deletions server/server/listener/mtmqtt.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from server.listener.mt.reader import import_mtconnect_data
from . import status

logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s:%(message)s")
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s: %(message)s")
logger = logging.getLogger(__name__)


Expand Down Expand Up @@ -141,8 +141,11 @@ def on_connect(client, userdata, flags, rc):
def on_message(client, userdata, msg):
if msg.topic == mqtt_listener.topic:
try:
row = mqtt_listener.parse_mtct_data(msg.payload.decode("utf-8"))
mt_data_list.append(row)
_current_row = mqtt_listener.parse_mtct_data(
msg.payload.decode("utf-8")
)
if len(mt_data_list) == 0 or mt_data_list[-1] != _current_row:
mt_data_list.append(_current_row)
except json.decoder.JSONDecodeError:
logger.warning("Failed to decode JSON payload")
status.update_process_status(
Expand Down
3 changes: 3 additions & 0 deletions server/server/mark/edge.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ def get_edges(mysql_config: dict, model_id: int):


def get_edges_by_side_id(side_id: int, mysql_config: dict, process_id: int):
"""
Get edge results by side_id and process_id
"""
cnx = mysql.connector.connect(**mysql_config, database="coord")
cursor = cnx.cursor()
query = (
Expand Down
37 changes: 26 additions & 11 deletions server/server/mark/line.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,20 +56,36 @@ def to_side_list(model_id: int, pairs: np.ndarray, pair_id: int):
return side_list


def point_to_line_distance(line_points, point):
assert len(line_points) == 2, "line_points must have two points"
A = line_points[0]
B = line_points[1]
P = point

# Calculate the vector AP and vector AB
AP = P - A
AB = B - A

# Calculate the cross product (AP x AB)
cross_product = np.cross(AP, AB)

# Calculate the distance
distance = np.linalg.norm(cross_product) / np.linalg.norm(AB)

return distance


def import_sides(model_id: int, pairs: np.ndarray, pair_type: str, mysql_config: dict):
cnx = mysql.connector.connect(**mysql_config, database="coord")
cursor = cnx.cursor()
for pair in pairs:
pair_id = import_pair(model_id, pair_type, mysql_config)
pair_id = import_pair(model_id, pair_type, pair, cnx, cursor)
side_list = to_side_list(model_id, pair, pair_id)
insert_query = (
"INSERT INTO side (x0, y0, z0, x1, y1, z1, model_id, pair_id)"
" VALUES (%s, %s, %s, %s, %s, %s, %s, %s)"
)
try:
cursor.executemany(insert_query, side_list)
except IntegrityError:
print("Error: unable to import lines")
cursor.executemany(insert_query, side_list)
cnx.commit()
cursor.close()
cnx.close()
Expand Down Expand Up @@ -200,20 +216,19 @@ def import_lines_from_paired_lines_on_facets(
import_edges_from_sides(sides, mysql_config)


def import_pair(model_id: int, pair_type: str, mysql_config: dict) -> int:
cnx = mysql.connector.connect(**mysql_config, database="coord")
cursor = cnx.cursor()
insert_query = "INSERT INTO pair (model_id, type) VALUES (%s, %s)"
def import_pair(model_id: int, pair_type: str, pair, cnx, cursor) -> int:
assert len(pair) == 2, "pair must have two lines"
length = point_to_line_distance(pair[0], pair[1][0])
insert_query = "INSERT INTO pair (model_id, type, length) VALUES (%s, %s, %s)"
cursor.execute(
insert_query,
(
model_id,
pair_type,
length,
),
)
cnx.commit()
cursor.close()
cnx.close()
return cursor.lastrowid


Expand Down
119 changes: 59 additions & 60 deletions server/server/mark/pair.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import math
import numpy as np
import mysql.connector
from .edge import get_edges_by_side_id
from itertools import combinations


def get_pairs(model_id: int, mysql_config: dict):
Expand All @@ -14,40 +15,36 @@ def get_pairs(model_id: int, mysql_config: dict):
return pairs


def point_to_line_distance(edges_on_the_same_line: list, point: tuple):
[line_point1, line_point2] = edges_on_the_same_line
x1, y1, z1 = line_point1
x2, y2, z2 = line_point2
x, y, z = point
def point_to_line_distance(edges_on_the_same_line, point):
"""
Calculate the distance between a point and a line
# Calculate the direction vector of the line
line_direction = (x2 - x1, y2 - y1, z2 - z1)
Parameters
----------
edges_on_the_same_line : list
list of two edges on the same line
point : list
list of the point
# Calculate the vector from line_point1 to the point
to_point_vector = (x - x1, y - y1, z - z1)
Returns
-------
float
distance between the point and the line
"""
line_point1, line_point2 = edges_on_the_same_line
A = np.array(line_point1)
B = np.array(line_point2)
P = np.array(point)

# Calculate the dot product of the to_point_vector and the line_direction
dot_product = sum(a * b for a, b in zip(to_point_vector, line_direction))
# Calculate the vector AP and vector AB
AP = P - A
AB = B - A

# Calculate the magnitude of the line_direction vector squared
line_length_squared = sum(a * a for a in line_direction)
# Calculate the cross product (AP x AB)
cross_product = np.cross(AP, AB)

# Calculate the parameter t, which is the distance
# along the line to the closest point
t = dot_product / line_length_squared

if t < 0:
# Closest point is the first line endpoint
closest_point = line_point1
elif t > 1:
# Closest point is the second line endpoint
closest_point = line_point2
else:
# Closest point is along the line
closest_point = (x1 + t * (x2 - x1), y1 + t * (y2 - y1), z1 + t * (z2 - z1))

# Calculate the distance between the point and the closest point on the line
distance = math.sqrt(sum((a - b) ** 2 for a, b in zip(point, closest_point)))
# Calculate the distance
distance = np.linalg.norm(cross_product) / np.linalg.norm(AB)

return distance

Expand All @@ -62,22 +59,31 @@ def unique_tuples(list_of_tuples):
return unique_tuples


def validate_measured_edges(edges1, edges2):
edges1 = unique_tuples(edges1)
edges2 = unique_tuples(edges2)
def to_line_edge_list(edge_results1, edge_results2):
line_edge_list = []
edges1 = unique_tuples(edge_results1)
edges2 = unique_tuples(edge_results2)
if not edges1 or not edges2:
return []
edge1_count = len(edges1)
edge2_count = len(edges2)
if edge1_count == 2 and edge2_count == 2:
return [
[edges1, edges2[0]],
[edges1, edges2[1]],
[edges2, edges1[0]],
[edges2, edges1[1]],
]
if edge1_count == 2 and edge2_count == 1:
return [[edges1, edges2[0]]]
if edge2_count == 2 and edge1_count == 1:
return [[edges2, edges1[0]]]
if edge1_count == 1 and edge2_count == 1:
return []
if edge1_count > 1:
# add two of edges1 and one of edges2
# combinations of edges1
for i, j in combinations(range(edge1_count), 2):
for edge2 in edges2:
line_edge_list.append([[edges1[i], edges1[j]], edge2])

if edge2_count > 1:
# add two of edges2 and one of edges1
# combinations of edges2
for i, j in combinations(range(edge2_count), 2):
for edge1 in edges1:
line_edge_list.append([[edges2[i], edges2[j]], edge1])

return line_edge_list


def add_line_length(model_id: int, mysql_config: dict, process_id: int):
Expand All @@ -86,23 +92,21 @@ def add_line_length(model_id: int, mysql_config: dict, process_id: int):
sides = get_sides_by_pair_id(pair_id, mysql_config)
side1 = sides[0]
side2 = sides[1]
length = point_to_line_distance([side1[0:3], side1[3:6]], side2[0:3])
total_measured_length = 0
edges1 = get_edges_by_side_id(side1[6], mysql_config, process_id)
edges2 = get_edges_by_side_id(side2[6], mysql_config, process_id)
sample_size = 0
line_edge_list = validate_measured_edges(edges1, edges2)
edge_results1 = get_edges_by_side_id(side1[6], mysql_config, process_id)
edge_results2 = get_edges_by_side_id(side2[6], mysql_config, process_id)
line_edge_list = to_line_edge_list(edge_results1, edge_results2)
if not line_edge_list:
continue
distances = []
for [edges, edge] in line_edge_list:
# check if edge is not None
if edge and edge[0] and edge[1]:
sample_size += 1
total_measured_length += point_to_line_distance(edges, edge)
if sample_size == 0:
distances.append(point_to_line_distance(edges, edge))
if len(distances) == 0:
continue
measured_length = round(total_measured_length / sample_size, 3)
add_measured_length(pair_id, length, measured_length, mysql_config, process_id)
measured_length = np.mean(distances)
measured_length = float(np.round(measured_length, 3))
add_measured_length(pair_id, measured_length, mysql_config, process_id)


def get_sides_by_pair_id(pair_id: int, mysql_config: dict):
Expand All @@ -118,17 +122,12 @@ def get_sides_by_pair_id(pair_id: int, mysql_config: dict):

def add_measured_length(
pair_id: int,
length: float,
measured_length: float,
mysql_config: dict,
process_id: int,
):
cnx = mysql.connector.connect(**mysql_config, database="coord")
cursor = cnx.cursor()
query = "UPDATE pair SET length = %s WHERE id = %s"
cursor.execute(query, (length, pair_id))
cnx.commit()

query = "INSERT INTO pair_result (pair_id, process_id, length) VALUES (%s, %s, %s)"
cursor.execute(query, (pair_id, process_id, measured_length))
cnx.commit()
Expand Down
14 changes: 11 additions & 3 deletions server/server/measure/estimate.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
MQTT_USERNAME,
get_config,
)
from time import time
from server.mark.edge import (
import_edge_results,
delete_edge_results,
Expand All @@ -32,7 +33,7 @@
from scipy.ndimage import uniform_filter1d
import trimesh

logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s:%(message)s")
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s: %(message)s")
logger = logging.getLogger(__name__)


Expand All @@ -44,8 +45,8 @@ def __init__(self, mysql_config: dict, model_id: int, process_id: int):
self.conf = get_config()

self.mtct_data_checker = MtctDataChecker(mysql_config, model_id, process_id)
mtct_lines = self.mtct_data_checker.estimate_timestamps_from_mtct_data()
self.mtct_lines = self.mtct_data_checker.adjust_delays(mtct_lines)
self.mtct_lines = self.mtct_data_checker.estimate_timestamps_from_mtct_data()
# self.mtct_lines = self.mtct_data_checker.adjust_delays(mtct_lines)
sensor_data = get_sensor_data(process_id, mysql_config)
self.np_sensor_data = np.array(sensor_data)

Expand Down Expand Up @@ -244,17 +245,21 @@ def disconnect_and_publish_log(_msg: str):


def recompute(mysql_config: dict, process_id: int):
start_time = time()
logger.info("recompute() started")
# remove previous results
delete_edge_results(mysql_config, process_id)
arc.delete_measured_arc_info(mysql_config, process_id)
pair.delete_measured_length(mysql_config, process_id)
delete_trace_line_results(mysql_config, process_id)
update_mtct_latency(mysql_config, process_id, None)
logger.info("delete previous results")

process_data = status.get_process_status(mysql_config, process_id)
model_id = process_data[1]
result = Result(mysql_config, model_id, process_id)
edge_update_list, trace_line_update_list = result.compute_updating_data()
logger.info("compute_updating_data() done")

edge_count = len(edge_update_list)
if edge_count == 0:
Expand All @@ -264,8 +269,10 @@ def recompute(mysql_config: dict, process_id: int):
"Error at update_data_after_measurement()",
"No edge found",
)
logger.warning("No edge found")
return
import_edge_results(edge_update_list, mysql_config)
logger.info("import_edge_results() done")
if trace_line_update_list:
import_trace_line_results(mysql_config, trace_line_update_list)

Expand All @@ -277,6 +284,7 @@ def recompute(mysql_config: dict, process_id: int):
arc.add_measured_arc_info(model_id, mysql_config, process_id)
status.update_process_status(mysql_config, process_id, "done")
logger.info("done")
logger.info(f"recompute() took {time() - start_time} seconds")
except Exception as e:
logger.warning(e)
status.update_process_status(
Expand Down
Loading

0 comments on commit 6d2cfcc

Please sign in to comment.