diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a411422..761b6ea 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ jobs: steps: - name: Checkout Code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install SLOCCount run: sudo apt-get install sloccount - name: Check <1000 lines @@ -32,7 +32,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: @@ -80,7 +80,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install Blender run: sudo snap install blender --classic diff --git a/cnceye/config.py b/cnceye/config.py index a3d859a..932b7ee 100644 --- a/cnceye/config.py +++ b/cnceye/config.py @@ -10,10 +10,10 @@ MYSQL_CONFIG = dict( - host="raspberrypi.local", + host="192.168.122.76", port=3306, - user="yuchi", - password="raspberrypi", + user="root", + password="root", ) if os.environ.get("CI"): diff --git a/cnceye/edge/find.py b/cnceye/edge/find.py index 0ce28dd..c0ff1e7 100644 --- a/cnceye/edge/find.py +++ b/cnceye/edge/find.py @@ -1,4 +1,9 @@ import csv +import sqlite3 +import mysql.connector +from mysql.connector.errors import IntegrityError + +from cnceye.config import MYSQL_CONFIG def find_edge(filepath: str, minimal_diff: float = 5.0): @@ -17,6 +22,23 @@ def find_edge(filepath: str, minimal_diff: float = 5.0): previous_distance = distance +def find_edges_from_sqlite(database_path: str, minimal_diff: float = 5.0): + conn = sqlite3.connect(database_path) + cur = conn.cursor() + previous_distance = "" + edges = [] + for row in cur.execute("SELECT * FROM coord"): + # x, y, z, distance + distance = row[4] + if check_if_edge_is_found(distance, previous_distance, minimal_diff): + edges.append(row) + previous_distance = distance + + # remove the starting point + edges.pop(0) + return edges + + def check_if_edge_is_found( distance: str, prev_distance: str or float, minimal_diff: float = 5.0 ): @@ -56,3 +78,46 @@ def find_lines(filepath: str, edge_count: int, minimal_diff: float = 5.0): previous_row = row return lines + + +def get_edge_data(): + cnx = mysql.connector.connect(**MYSQL_CONFIG, database="coord") + cursor = cnx.cursor() + query = "SELECT id,side_id,x,y,z FROM edge" + cursor.execute(query) + edges = cursor.fetchall() + cursor.close() + cnx.close() + return edges + + +def identify_close_edge(edges, measured_edges, distance_threshold=2.5): + update_list = [] + for id, side_id, x, y, z in edges: + min_distance = 999999.0 + data_with_min_distance = [] + for measured_edge in measured_edges: + rx = measured_edge[1] + ry = measured_edge[2] + distance = ((x - rx) ** 2 + (y - ry) ** 2) ** 0.5 + if distance < min_distance: + min_distance = distance + data_with_min_distance = (rx, ry, z, id) + + if min_distance <= distance_threshold: + update_list.append(data_with_min_distance) + + return update_list + + +def add_measured_edge_coord(edge_list: list): + cnx = mysql.connector.connect(**MYSQL_CONFIG, database="coord") + cursor = cnx.cursor() + insert_query = "UPDATE edge SET rx = %s, ry = %s, rz = %s WHERE id = %s" + try: + cursor.executemany(insert_query, edge_list) + except IntegrityError: + print("Error: unable to import lines") + cnx.commit() + cursor.close() + cnx.close() diff --git a/mysql/init.sql b/mysql/init.sql index 4026e92..f9de8d6 100644 --- a/mysql/init.sql +++ b/mysql/init.sql @@ -38,4 +38,28 @@ CREATE TABLE IF NOT EXISTS `arc` ( `rcy` FLOAT, `rcz` FLOAT, PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1; + +CREATE TABLE IF NOT EXISTS `edge` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `side_id` int(11) unsigned NOT NULL, + `x` FLOAT NOT NULL, + `y` FLOAT NOT NULL, + `z` FLOAT NOT NULL, + `rx` FLOAT, + `ry` FLOAT, + `rz` FLOAT, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1; + +CREATE TABLE IF NOT EXISTS `side` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `x0` FLOAT NOT NULL, + `y0` FLOAT NOT NULL, + `z0` FLOAT NOT NULL, + `x1` FLOAT NOT NULL, + `y1` FLOAT NOT NULL, + `z1` FLOAT NOT NULL, + `pair_id` int(11) unsigned, + PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1; \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index c968fad..cedc773 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "cnceye" -version = "0.2.0" +version = "0.3.0" description = "" authors = ["yuichiroaoki <45054071+yuichiroaoki@users.noreply.github.com>"] readme = "README.md" diff --git a/scripts/simple_measurement.py b/scripts/simple_measurement.py new file mode 100644 index 0000000..f5beb94 --- /dev/null +++ b/scripts/simple_measurement.py @@ -0,0 +1,99 @@ +""" +Simulate the measurement of the 3D model by moving the sensor with G-code +""" +import bpy +from mathutils import Vector +import sqlite3 +import csv +import sys + +# Get the active object (the 3D model) +obj = bpy.data.objects["test-part"] + +ray_direction = Vector((0, 0, -1)) + +# x, y, z, distance +data = [] + +# Ensure the object has a mesh +assert obj.type == "MESH" + + +def distance_to_analog_output(distance: float): + distance = distance * 1000 * 135 # m to mm, distance to analog output + return float(round(distance)) + + +def load_gcode(filepath: str): + with open(filepath, newline="") as csvfile: + reader = csv.reader(csvfile, delimiter=" ") + gcode = list(reader) + gcode.pop(0) + gcode.pop() + return gcode + + +def move_start_point(_start_point, xyz, feedrate: float): + """ + Move the start point to the given direction + _start_point: Vector (x, y, z) in m (relative to obj.location) + xyz: tuple (x, y, z) in mm + feedrate: float (mm/min) + sensor response time is 10ms + """ + one_step_distance = feedrate / 1000 / 60 * 0.01 # m/step + destination = Vector(tuple([x / 1000 for x in xyz])) + total_distance_to_move = (destination - _start_point).length + loop_count = int(total_distance_to_move // one_step_distance) + move_vector = (destination - _start_point) / loop_count + for _ in range(loop_count): + distance = 0.14 # 140 mm + # Calculate the intersection point with the face + (hit, intersection_point, *_) = obj.ray_cast(_start_point, ray_direction) + + if hit: + distance = start_point[2] - intersection_point[2] + + # m to mm and round to 3 decimal places + xyz = [_start_point.x, _start_point.y, _start_point.z] + xyz = [round(x * 1000, 3) for x in xyz] + + data.append([*xyz, distance_to_analog_output(distance)]) + _start_point = _start_point + move_vector + + return destination # _start_point not may not become exactly the destination + + +def row_to_xyz_feedrate(row): + x = float(row[1][1:]) + y = float(row[2][1:]) + z = float(row[3][1:]) + feedrate = float(row[4][1:]) + return (x, y, z, feedrate) + + +# get filepath from arguments +argv = sys.argv +argv = argv[argv.index("--") + 1 :] +assert len(argv) == 1 +gcode = load_gcode(argv[0]) + +# Define the ray's starting point in object space +first_row = gcode[0] +(x, y, z, feedrate) = row_to_xyz_feedrate(first_row) +start_point = Vector((x / 1000, y / 1000, 0.206)) + + +# start_point = Vector(initial_coord) - obj.location +gcode = gcode[1:] + +for row in gcode: + (x, y, z, feedrate) = row_to_xyz_feedrate(row) + z = 206.0 # ignore z + start_point = move_start_point(start_point, (x, y, z), feedrate) + +conn = sqlite3.connect("listener.db") +cur = conn.cursor() +cur.executemany("INSERT INTO coord(x, y, z, distance) VALUES (?, ?, ?, ?)", data) +conn.commit() +conn.close() diff --git a/tests/fixtures/db/listener.db b/tests/fixtures/db/listener.db new file mode 100644 index 0000000..cf0205b Binary files /dev/null and b/tests/fixtures/db/listener.db differ diff --git a/tests/fixtures/gcode/edge.gcode b/tests/fixtures/gcode/edge.gcode new file mode 100644 index 0000000..74c9107 --- /dev/null +++ b/tests/fixtures/gcode/edge.gcode @@ -0,0 +1,18 @@ +O0001 +G1 X-52.5 Y0.0 Z10.0 F600 +G1 X-47.5 Y0.0 Z10.0 F300 +G1 X-27.5 Y38.0 Z10.0 F600 +G1 X-22.5 Y38.0 Z10.0 F300 +G1 X0.0 Y-67.5 Z10.0 F600 +G1 X0.0 Y-62.5 Z10.0 F300 +G1 X0.0 Y20.5 Z10.0 F600 +G1 X0.0 Y25.5 Z10.0 F300 +G1 X0.0 Y50.5 Z10.0 F600 +G1 X0.0 Y55.5 Z10.0 F300 +G1 X0.0 Y62.5 Z10.0 F600 +G1 X0.0 Y67.5 Z10.0 F300 +G1 X22.5 Y38.0 Z10.0 F600 +G1 X27.5 Y38.0 Z10.0 F300 +G1 X47.5 Y0.0 Z10.0 F600 +G1 X52.5 Y0.0 Z10.0 F300 +M30 diff --git a/tests/test_find.py b/tests/test_find.py index 051e76a..046fb28 100644 --- a/tests/test_find.py +++ b/tests/test_find.py @@ -7,6 +7,31 @@ def test_find_edge(): print(edge_position) +def test_find_edge_from_sqlite(): + db_path = "tests/fixtures/db/listener.db" + measured_edges = find.find_edges_from_sqlite(db_path, 100.0) + print(measured_edges) + assert len(measured_edges) == 16 + + +def test_add_measured_edge_coord(): + db_path = "tests/fixtures/db/listener.db" + measured_edges = find.find_edges_from_sqlite(db_path, 100.0) + edge_data = [ + (1, 6, -50.0, 0.0, 10.0), + (2, 8, -25.0, 38.0, 10.0), + (3, 2, 0.0, -65.0, 10.0), + (4, 3, 0.0, 23.0, 10.0), + (5, 4, 0.0, 53.0, 10.0), + (6, 1, 0.0, 65.0, 10.0), + (7, 7, 25.0, 38.0, 10.0), + (8, 5, 50.0, 0.0, 10.0), + ] + # edge_data = find.get_edge_data() + update_list = find.identify_close_edge(edge_data, measured_edges) + find.add_measured_edge_coord(update_list) + + def test_check_if_edge_is_found(): assert find.check_if_edge_is_found("", "") is False assert find.check_if_edge_is_found("", 100.0) is True