Strona główna ASTOR
Automatyka w praktyce

Stanowisko do grawerowania laserowego z wykorzystaniem robota edukacyjnego Astorino

Kontakt w sprawie artykułu: Kamila Piechocka - 2025-10-01

Przedstawiamy projekt opracowany przez studentów w ramach Koła Naukowego Robotyka Automatyka Informatyka (KN RAI) w Instytucie Automatyki i Robotyki na Politechnice Poznańskiej.

Projekt zrealizowali studenci Politechniki Poznańskiej: Jakub Sadurski, Wiktor Stachowski, Daniel Stasiak.

Opiekunem projektu był dr inż. Paweł Szulczyński, adiunkt Zakładu Sterowania i Robotyki (Z1).

Plan realizacji projektu

(kliknij, aby powiększyć)

Plan stanowiska

1. Komputer PC wysyła komendy ruchu czasu rzeczywistego RTC, zawierające położenie następnego punktu, pozycje narzędzia, czas na wykonanie danego ruchu oraz sygnał sterujący laserem.

2. Astorino zwraca informacje o zakończeniu danego ruchu – funkcja blokująca.

3. Arduino Nano przelicza sygnały I/O z Astorino na wypełnienie PWM dla lasera.

4. Laser NEJE reguluje moc na podstawie sygnału PWM z Arduino.

Zastosowane mocowania

1. Holder Arduino.

2. Holder sterownika lasera.

3. Przejściówka robot – laser.

Rzeczywisty wygląd stanowiska

(kliknij, aby powiększyć)

Algorytm programu

(kliknij, aby powiększyć)

Wygląd aplikacji

Przetwarzanie obrazu – program w języku Python

(kliknij, aby powiększyć)

Kod przetwarzania obrazu

# --- Parametry ---
img_path = sys.argv[1]
target_width = 2000 # px
target_height = 2000 # px
scale = 200.0 / 2000.0   # skalowanie (mm/px)

step_contour_mm = 0.1   # odstęp punktów wewnątrz konturu (mm)
step_between_mm = 0.2  # odstęp punktów między konturami (mm)

# --- Wczytanie i przygotowanie obrazu ---
img_og = cv2.imread(img_path)
img = cv2.resize(img_og, (target_width, target_height))
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(img_gray, 192, 255, cv2.THRESH_BINARY)
thresh_invert = cv2.bitwise_not(thresh)

contours, hierarchy = cv2.findContours(thresh_invert, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)

Generowanie trajektorii – program w języku Python

Przykładowe wygenerowane ścieżki robota

Fragment kodu Python odpowiedzialnego za trajektorię

path = []
prev_last_point = None

for contour in contours:
    # Skalowanie konturu do mm
    contour_mm = contour.reshape(-1, 2).astype(float)
    contour_mm[:, 0] *= scale  # x
    contour_mm[:, 1] *= -scale  # y odwrócone

    # Interpolacja punktów
    resampled_contour = resample_path(contour_mm, step_contour_mm)

    # Punkty między konturami
    if prev_last_point is not None:
        move_between = resample_path([prev_last_point, resampled_contour[0]], step_between_mm)
        for pt in move_between:
            path.append([round(pt[0], 1), round(pt[1], 1), 2])  # 2 = między konturami

    # Punkty wewnątrz konturu
    for pt in resampled_contour:
        path.append([round(pt[0], 1), round(pt[1], 1), 1])  # 1 = kontur

    prev_last_point = resampled_contour[-1]

# Dodanie tagów aktywacji/deaktywacji lasera
fix_tags(path)

print(f"Liczba punktów w ścieżce: {len(path)}")

Interpolacja punktów

def resample_path(points, step):
    """
    Interpoluje punkty na ścieżce tak, aby odstępy między nimi były równe 'step' [mm].

    points: lista punktów (x, y) [mm]
    step: krok między punktami [mm]
    return: lista punktów (x, y) w odstępach step [mm]
    """
    points = np.array(points)
    resampled = [points[0]]
    acc_dist = 0.0

    for i in range(1, len(points)):
        p0 = points[i - 1]
        p1 = points[i]
        segment_vec = p1 - p0
        segment_len = np.linalg.norm(segment_vec)

        while acc_dist + segment_len >= step and segment_len > 1e-12:
            ratio = (step - acc_dist) / segment_len
            new_point = p0 + ratio * segment_vec
            resampled.append(new_point)
            p0 = new_point
            segment_vec = p1 - p0
            segment_len = np.linalg.norm(segment_vec)
            acc_dist = 0.0

        acc_dist += segment_len

    # Dodaj ostatni punkt (koniec konturu)
    if not np.allclose(resampled[-1], points[-1]):
        resampled.append(points[-1])
    return np.array(resampled)

Realizacja trajektorii na robocie – program w języku C#

Pętla realizująca trajektorię

// Pętla trajektorii
for (int i = 1; i < points.Count; i++)
{
	if (token.IsCancellationRequested)
		throw new OperationCanceledException("Użytkownik przerwał trajektorię.");
	var pt = points[i];
	double[] target = { pt.x + x_offset, pt.y + y_offset, tool_height, orientation[0], orientation[1], orientation[2] };
	r.RTC_move(0x01, 10, target); // Nowy punkt wczytywany co 10ms
								  
	if (pt.tag == 3)
	{
		r.setOutput(5, 1);
		Invoke(() => listBox1.Items.Add("Laser ON"));
	}
	if (pt.tag == 4)
	{
		r.setOutput(5, -1);  
		Invoke(() => listBox1.Items.Add("Laser OFF"));
	}
	Invoke(() =>
	{
		listBox1.Items.Add($"{i}. X: {pt.x:F1}, Y: {pt.y:F1}, tag: {pt.tag}");
		listBox1.SelectedIndex = listBox1.Items.Count - 1; // autoscroll
		listBox1.ClearSelected();
	});
}
Invoke(() => MessageBox.Show("Trajektoria zakończona."));

Prezentacja działania stanowiska

Newsletter Poradnika Automatyka

Czytaj trendy i inspiracje, podstawy automatyki, automatykę w praktyce

Please wait...

Dziękujemy za zapis do newslettera!

Czy ten artykuł był dla Ciebie przydatny?

Średnia ocena artykułu: 0 / 5. Ilość ocen: 0

Ten artykuł nie był jeszcze oceniony.

Zadaj pytanie

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *