Skip to content

Commit

Permalink
Gcode (#14)
Browse files Browse the repository at this point in the history
* fix load gcode

* update readme

* fmt

* update readme
  • Loading branch information
yuichiroaoki authored Oct 17, 2023
1 parent f0a7fbb commit f3f76f4
Show file tree
Hide file tree
Showing 8 changed files with 120 additions and 10 deletions.
8 changes: 3 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
# cnceye
![Test](https://github.com/OpenCMM/cnceye/actions/workflows/ci.yml/badge.svg)

Cnceye indentifies the actual coordiantes of each vertex of a product from a image.
From there, it will measure the dimensions of the product. Our goal is to make this process as easy as possible with less than 1 micro precision.
cnceye measures the dimensions of a workpiece using the a laser triagulation sensor on a CNC machine.

![a laser triagulation sensor](https://opencmm.xyz/assets/images/sensor-55b7cf98350f293eba2c2b9d593bdd4f.png)

## Simulation with Blender
Create test data

Prerequisites
- Blender 3.6.1 or later

Change the output path in `scripts/create_test_images.py` and run

```bash
blender "blender/example.blend" --background --python scripts/create_test_images.py
blender "blender/measure.blend" --background --python scripts/demo.py -- tests/fixtures/gcode/edge.gcode
```
Binary file added blender/measure.blend
Binary file not shown.
4 changes: 2 additions & 2 deletions cnceye/edge/find.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,9 @@ def identify_close_edge(edges, measured_edges, distance_threshold=2.5):
def add_measured_edge_coord(edge_list: list, mysql_config=MYSQL_CONFIG):
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"
query = "UPDATE edge SET rx = %s, ry = %s, rz = %s WHERE id = %s"
try:
cursor.executemany(insert_query, edge_list)
cursor.executemany(query, edge_list)
except IntegrityError:
print("Error: unable to import lines")
cnx.commit()
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "cnceye"
version = "0.3.1"
version = "0.3.2"
description = "CMM python library"
license = "MIT"
authors = ["yuichiroaoki <45054071+yuichiroaoki@users.noreply.github.com>"]
Expand Down
96 changes: 96 additions & 0 deletions scripts/demo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
"""
Simulate the measurement of the 3D model by moving the sensor with G-code
"""
import bpy
from mathutils import Vector
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 = gcode[2:-2]
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)

# save as csv
with open("demo.csv", "w", newline="") as csvfile:
writer = csv.writer(csvfile, delimiter=",")
writer.writerows(data)
3 changes: 1 addition & 2 deletions scripts/simple_measurement.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ def load_gcode(filepath: str):
with open(filepath, newline="") as csvfile:
reader = csv.reader(csvfile, delimiter=" ")
gcode = list(reader)
gcode.pop(0)
gcode.pop()
gcode = gcode[2:-2]
return gcode


Expand Down
2 changes: 2 additions & 0 deletions tests/fixtures/gcode/edge.gcode
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
%
O0001
G1 X-52.5 Y0.0 Z10.0 F600
G1 X-47.5 Y0.0 Z10.0 F300
Expand All @@ -16,3 +17,4 @@ 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
%
15 changes: 15 additions & 0 deletions tests/test_gcode.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import csv


def load_gcode(filepath: str):
with open(filepath, newline="") as csvfile:
reader = csv.reader(csvfile, delimiter=" ")
gcode = list(reader)
gcode = gcode[2:-2]
return gcode


def test_load_gcode():
filepath = "tests/fixtures/gcode/edge.gcode"
gcode = load_gcode(filepath)
assert len(gcode) == 16

0 comments on commit f3f76f4

Please sign in to comment.