mercoledì 26 novembre 2025

Broken Debian Update

Aggiornamento

 Si sono perse anche le configurazioni di Cups...niente di drammatico, solo fastidioso

-------------------------------------------- 

Diciamocelo...e' talmente tanto che accada che quando succede fa notizie

Ieri sera aggiornamento automatico di Debian al riavvio della macchina ed impossibilita' di loggarsi

Per un caso fortuito oltre a Gnome ho installato I3 ed entrando con questo window manager funzionava tutto...l'attenzione e' andata tutta su Gnome che infatti risultava rotto

Ho cancellato le estensioni ed e' partito ma rimangono ancora problemi occasionali ma non cosi' gravi da non poter utilizzare la macchina

Di seguito il log dell'errore 

 

===========================================================
[   68.164837] VBoxNetAdp: Successfully started.
[   91.779137] traps: gnome-session-i[3594] trap int3 ip:7fc415d3074b sp:7ffd5e4b5020 error:0 in libglib-2.0.so.0.8600.2[6874b,7fc415ce7000+a5000]
[   92.781729] slim[3069]: segfault at 0 ip 00007f7e55d33c7f sp 00007ffc0e775f70 error 4 in libX11.so.6.4.0[45c7f,7f7e55d0a000+90000] likely on CPU 1 (core 1, socket 0)
[   92.781740] Code: 00 48 89 fd 49 89 f5 48 89 d3 48 39 87 b0 00 00 00 75 09 48 85 d2 0f 84 28 01 00 00 48 8b 85 30 0a 00 00 4c 8b a5 98 00 00 00 <48> 8b 38 8b 48 48 48 8b 50 40 48 89 3c 24 85 c9 0f 84 2b 01 00 00
[   93.008089] audit: type=1400 audit(1764098950.300:196): apparmor="ALLOWED" operation="capable" class="cap" profile="Xorg" pid=3759 comm="Xorg" capability=12  capname="net_admin"
[   93.009749] audit: type=1400 audit(1764098950.300:197): apparmor="ALLOWED" operation="capable" class="cap" profile="Xorg" pid=3759 comm="Xorg" capability=26  capname="sys_tty_config"
[   93.273176] audit: type=1400 audit(1764098950.564:198): apparmor="ALLOWED" operation="capable" class="cap" profile="Xorg" pid=3759 comm="Xorg" capability=12  capname="net_admin"
[  136.816358] traps: gnome-session-i[3829] trap int3 ip:7fde4053a74b sp:7ffebe209ba0 error:0 in libglib-2.0.so.0.8600.2[6874b,7fde404f1000+a5000]
[  137.818699] slim[3756]: segfault at 50 ip 00007f658ae0724c sp 00007fff6224c220 error 4 in libX11.so.6.4.0[4624c,7f658addd000+90000] likely on CPU 0 (core 0, socket 0)
[  137.818711] Code: 28 00 00 00 75 06 48 83 c4 10 5b c3 e8 fd 68 fd ff 66 66 2e 0f 1f 84 00 00 00 00 00 66 90 f3 0f 1e fa 53 48 8b 87 30 0a 00 00 <48> 8b 58 50 48 83 fb ff 0f 84 68 8c fd ff 48 c7 40 50 ff ff ff ff
[  138.017888] audit: type=1400 audit(1764098995.309:199): apparmor="ALLOWED" operation="capable" class="cap" profile="Xorg" pid=3994 comm="Xorg" capability=12  capname="net_admin"
[  138.020324] audit: type=1400 audit(1764098995.313:200): apparmor="ALLOWED" operation="capable" class="cap" profile="Xorg" pid=3994 comm="Xorg" capability=26  capname="sys_tty_config"
[  150.175775] traps: gnome-session-i[4069] trap int3 ip:7f8f60a9474b sp:7ffcbe8a94a0 error:0 in libglib-2.0.so.0.8600.2[6874b,7f8f60a4b000+a5000]
[  151.178115] slim[3991]: segfault at 50 ip 00007ffbca41824c sp 00007ffc84aeb9b0 error 4 in libX11.so.6.4.0[4624c,7ffbca3ee000+90000] likely on CPU 2 (core 0, socket 0)
[  151.178127] Code: 28 00 00 00 75 06 48 83 c4 10 5b c3 e8 fd 68 fd ff 66 66 2e 0f 1f 84 00 00 00 00 00 66 90 f3 0f 1e fa 53 48 8b 87 30 0a 00 00 <48> 8b 58 50 

martedì 25 novembre 2025

Disegnatore robot a pantografo

 Questo post deriva dalla curiosita' suscitata dal giocattolo Lisciani Step

 

 

 

 


 

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

# ---------------------------------------------------------
# PARAMETRI DEL PANTOGRAFO
# ---------------------------------------------------------

L = 1.0          # lunghezza dei bracci
cx, cy = 0.5, 0.5    # centro del cerchio
R = 0.3          # raggio del cerchio (deve essere <= 2L)
omega = 1.0      # velocità angolare

# ---------------------------------------------------------
# TRAIETTORIA DEL PENNINO
# ---------------------------------------------------------

t = np.linspace(0, 6*np.pi, 600)

Px = cx + R * np.cos(omega * t)
Py = cy + R * np.sin(omega * t)

# ---------------------------------------------------------
# Cinematica inversa (soluzione simmetrica)
# ---------------------------------------------------------
def inv_kin(px, py):
    p = np.array([px, py]) / L
    rho = np.linalg.norm(p)

    if rho > 2:
        raise ValueError("Punto fuori dal workspace del pantografo: ", (px,py))

    phi = np.arctan2(p[1], p[0])
    alpha = np.arccos(rho / 2)

    theta1 = phi + alpha
    theta2 = phi - alpha

    return theta1, theta2

# ---------------------------------------------------------
# Calcolo posizioni dei giunti A, B e del punto P
# ---------------------------------------------------------

A, B, P = [], [], []

for px, py in zip(Px, Py):
    th1, th2 = inv_kin(px, py)

    a = np.array([L*np.cos(th1), L*np.sin(th1)])
    b = np.array([L*np.cos(th2), L*np.sin(th2)])
    p = a + b

    A.append(a)
    B.append(b)
    P.append(p)

A = np.array(A)
B = np.array(B)
P = np.array(P)

# ---------------------------------------------------------
# ANIMAZIONE
# ---------------------------------------------------------

fig, ax = plt.subplots(figsize=(6,6))
ax.set_xlim(-1.5, 1.5)
ax.set_ylim(-1.5, 1.5)
ax.set_aspect('equal')
ax.set_title("Pantografo – cerchio centrato in (0.5, 0.5) r=0.3")

line_OA, = ax.plot([], [], lw=2)
line_OB, = ax.plot([], [], lw=2)
line_AP, = ax.plot([], [], lw=1, ls='--')
line_BP, = ax.plot([], [], lw=1, ls='--')
pen,      = ax.plot([], [], 'o')
traj,     = ax.plot(P[:,0], P[:,1], alpha=0.2)

def init():
    line_OA.set_data([], [])
    line_OB.set_data([], [])
    line_AP.set_data([], [])
    line_BP.set_data([], [])
    pen.set_data([], [])
    return line_OA, line_OB, line_AP, line_BP, pen

def update(i):
    O = np.array([0,0])
    a = A[i]
    b = B[i]
    p = P[i]

    line_OA.set_data([O[0], a[0]], [O[1], a[1]])
    line_OB.set_data([O[0], b[0]], [O[1], b[1]])
    line_AP.set_data([a[0], p[0]], [a[1], p[1]])
    line_BP.set_data([b[0], p[0]], [b[1], p[1]])

    # FIX richiesto da Matplotlib: sequenze, non scalari
    pen.set_data([p[0]], [p[1]])

    return line_OA, line_OB, line_AP, line_BP, pen

ani = FuncAnimation(fig, update, frames=len(t), init_func=init, blit=True)
plt.show()


 

 

 

domenica 23 novembre 2025

Cinematica Inversa su braccio robotico

Mi sono messo a leggiucchiare il libro Robotica: Modellistica, Pianificazione e Controllo (Bruno Siciliano,Lorenzo Sciavicco,Luigi Villani, Giuseppe Oriolo McGraw-Hill Libri Italia srl) ...leggiucchiare perche' e' un libro di teoria di robot pieno di matematica

 

Partendo dalle misure e dalla forma di un robot reale (braccio robotico antropomorfo tinkerkit a 5 gradi di liberta' piu' presa) con l'idea di tracciare una traiettoria circolare sul pavimento

In questo tipo si esercizio si definisce l'obbiettivo e si lascia all'algoritmo il calcolo della posa del robot


 

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.animation as animation

# --- 1. MOTORE CINEMATICO (IK) ---
def cinematica_inversa_3R_planare(r, z, phi_deg, L1, L2, L3):
phi_rad = np.deg2rad(phi_deg)
# Calcolo posizione polso
# Con phi = -90, cos(-90)=0 e sin(-90)=-1
# Quindi w_r = r e w_z = z + L3
w_r = r - L3 * np.cos(phi_rad)
w_z = z - L3 * np.sin(phi_rad)
dist_sq = w_r**2 + w_z**2
# Teorema Coseno per Gomito
cos_theta2 = (dist_sq - L1**2 - L2**2) / (2 * L1 * L2)
if abs(cos_theta2) > 1: return []
soluzioni = []
for sigma in [1, -1]:
sin_theta2 = sigma * np.sqrt(1 - cos_theta2**2)
theta2 = np.arctan2(sin_theta2, cos_theta2)
alpha = np.arctan2(w_z, w_r)
beta = np.arctan2(L2 * np.sin(theta2), L1 + L2 * np.cos(theta2))
theta1 = alpha - beta
theta3 = phi_rad - theta1 - theta2
soluzioni.append((theta1, theta2, theta3))
return soluzioni

def ik_braccio(x, y, z, phi_pitch_deg, L_base, L_omero, L_ulna, L_mano):
theta_base = np.arctan2(y, x)
r_planare = np.sqrt(x**2 + y**2)
z_relativa = z - L_base
sols_2d = cinematica_inversa_3R_planare(r_planare, z_relativa, phi_pitch_deg, L_omero, L_ulna, L_mano)
return [(theta_base, t1, t2, t3) for (t1, t2, t3) in sols_2d]

def calcola_punti_robot(angles, L0, L1, L2, L3):
th_base, th_spalla, th_gomito, th_polso = angles
p0 = np.array([0, 0, 0]); p1 = np.array([0, 0, L0])
cos_b, sin_b = np.cos(th_base), np.sin(th_base)
r2 = L1 * np.cos(th_spalla); z2 = L0 + L1 * np.sin(th_spalla)
p2 = np.array([r2 * cos_b, r2 * sin_b, z2])
angle_cum = th_spalla + th_gomito
r3 = r2 + L2 * np.cos(angle_cum); z3 = z2 + L2 * np.sin(angle_cum)
p3 = np.array([r3 * cos_b, r3 * sin_b, z3])
angle_cum_tot = angle_cum + th_polso
r4 = r3 + L3 * np.cos(angle_cum_tot); z4 = z3 + L3 * np.sin(angle_cum_tot)
p4 = np.array([r4 * cos_b, r4 * sin_b, z4])
return np.array([p0, p1, p2, p3, p4])

# --- 2. LOGICA DI SELEZIONE OTTIMIZZATA ---
def scegli_soluzione_migliore(soluzioni, angoli_precedenti):
if not soluzioni: return None
migliore_sol = None
miglior_punteggio = -np.inf
for sol in soluzioni:
deviazione_gomito_rad = abs(sol[2])
# Criterio: Angolo aperto (>90 gradi interni)
score = 0
if deviazione_gomito_rad < np.pi/2:
score += 1000
else:
score -= 1000
if angoli_precedenti is not None:
diff = np.linalg.norm(np.array(sol) - np.array(angoli_precedenti))
score -= diff * 100
if score > miglior_punteggio:
miglior_punteggio = score
migliore_sol = sol
return migliore_sol

# --- 3. CONFIGURAZIONE PARAMETRI ---
L_BASE, L_OMERO, L_ULNA, L_MANO = 0.0715, 0.125, 0.125, 0.060

# >>> MODIFICA CHIAVE QUI <<<
# Impostiamo -90 gradi. Il polso punta verso il basso (asse -Z)
# Ortogonale al piano XY.
PHI_PITCH = -90

CENTER = np.array([0.15, 0.15, 0.0]) # Spostato un po' più avanti per facilitare la presa verticale
RADIUS = 0.03

# Home Position
HOME_POS = np.array([0.0, 0.15, 0.25])
START_CIRCLE = np.array([CENTER[0] + RADIUS, CENTER[1], CENTER[2]])

# Generazione Traiettoria
frames_approach = 40
traj_approach_x = np.linspace(HOME_POS[0], START_CIRCLE[0], frames_approach)
traj_approach_y = np.linspace(HOME_POS[1], START_CIRCLE[1], frames_approach)
traj_approach_z = np.linspace(HOME_POS[2], START_CIRCLE[2], frames_approach)

frames_circle = 80
angles = np.linspace(0, 2*np.pi, frames_circle)
traj_circle_x = CENTER[0] + RADIUS * np.cos(angles)
traj_circle_y = CENTER[1] + RADIUS * np.sin(angles)
traj_circle_z = np.full_like(angles, CENTER[2])

full_traj_x = np.concatenate([traj_approach_x, traj_circle_x])
full_traj_y = np.concatenate([traj_approach_y, traj_circle_y])
full_traj_z = np.concatenate([traj_approach_z, traj_circle_z])
TOTAL_FRAMES = len(full_traj_x)

# --- 4. ANIMAZIONE ---
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')
ax.set_xlim(-0.1, 0.3); ax.set_ylim(-0.1, 0.3); ax.set_zlim(0, 0.4)
ax.set_xlabel('X'); ax.set_ylabel('Y'); ax.set_zlabel('Z')
ax.set_title(f'Tinkerkit Braccio - Polso Verticale ({PHI_PITCH}°)')

line_robot, = ax.plot([], [], [], 'o-', lw=4, color='tab:blue', label='Robot')
point_target, = ax.plot([], [], [], 'X', color='red', label='Target')
line_trace, = ax.plot([], [], [], '-', lw=1, color='red', alpha=0.5)

# Disegniamo un piccolo piano XY per riferimento visivo
xx, yy = np.meshgrid(np.linspace(-0.1, 0.3, 2), np.linspace(-0.1, 0.3, 2))
ax.plot_surface(xx, yy, np.zeros_like(xx), alpha=0.2, color='gray')

ax.legend()

prev_angles = None
history_x, history_y, history_z = [], [], []

def update(frame_idx):
global prev_angles
tx = full_traj_x[frame_idx]
ty = full_traj_y[frame_idx]
tz = full_traj_z[frame_idx]
sols = ik_braccio(tx, ty, tz, PHI_PITCH, L_BASE, L_OMERO, L_ULNA, L_MANO)
best_sol = scegli_soluzione_migliore(sols, prev_angles)
if best_sol:
prev_angles = best_sol
points = calcola_punti_robot(best_sol, L_BASE, L_OMERO, L_ULNA, L_MANO)
line_robot.set_data(points[:,0], points[:,1])
line_robot.set_3d_properties(points[:,2])
point_target.set_data([tx], [ty])
point_target.set_3d_properties([tz])
history_x.append(tx); history_y.append(ty); history_z.append(tz)
line_trace.set_data(history_x, history_y)
line_trace.set_3d_properties(history_z)
return line_robot, point_target, line_trace

ani = animation.FuncAnimation(fig, update, frames=TOTAL_FRAMES, interval=40, blit=False, repeat=True)
plt.show()


 

 il braccio segue la traiettoria circolare ma muovendosi in uno spazio reale sbatterebbe il gomito sul pavimento...Mettiamo la condizione che i giunti debbano avere coordinata Z sempre positiva


import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.animation as animation

# --- 1. PARAMETRI E COSTANTI GLOBALI ---
L_BASE, L_OMERO, L_ULNA, L_MANO = 0.0715, 0.125, 0.125, 0.060
PHI_PITCH = -90 # Polso verticale
CENTER = np.array([0.15, 0.0, 0.0]) # Z target = 0.0, come richiesto
RADIUS = 0.03

# --- 2. FUNZIONI CINEMATICHE (Invariate) ---
def cinematica_inversa_3R_planare(r, z, phi_deg, L1, L2, L3):
phi_rad = np.deg2rad(phi_deg)
w_r = r - L3 * np.cos(phi_rad)
w_z = z - L3 * np.sin(phi_rad)
dist_sq = w_r**2 + w_z**2
cos_theta2 = (dist_sq - L1**2 - L2**2) / (2 * L1 * L2)
if abs(cos_theta2) > 1: return []
soluzioni = []
for sigma in [1, -1]:
sin_theta2 = sigma * np.sqrt(1 - cos_theta2**2)
theta2 = np.arctan2(sin_theta2, cos_theta2)
alpha = np.arctan2(w_z, w_r)
beta = np.arctan2(L2 * np.sin(theta2), L1 + L2 * np.cos(theta2))
theta1 = alpha - beta
theta3 = phi_rad - theta1 - theta2
soluzioni.append((theta1, theta2, theta3))
return soluzioni

def ik_braccio(x, y, z, phi_pitch_deg, L_base, L_omero, L_ulna, L_mano):
theta_base = np.arctan2(y, x)
r_planare = np.sqrt(x**2 + y**2)
z_relativa = z - L_base
sols_2d = cinematica_inversa_3R_planare(r_planare, z_relativa, phi_pitch_deg, L_omero, L_ulna, L_mano)
return [(theta_base, t1, t2, t3) for (t1, t2, t3) in sols_2d]

def calcola_punti_robot(angles):
# Uso le costanti globali L_BASE, L_OMERO, etc.
th_base, th_spalla, th_gomito, th_polso = angles
# P0 e P1 (Base e Spalla)
p0 = np.array([0, 0, 0]); p1 = np.array([0, 0, L_BASE])
# P2 (Gomito)
cos_b, sin_b = np.cos(th_base), np.sin(th_base)
r2 = L_OMERO * np.cos(th_spalla); z2 = L_BASE + L_OMERO * np.sin(th_spalla)
p2 = np.array([r2 * cos_b, r2 * sin_b, z2])
# P3 (Polso)
angle_cum = th_spalla + th_gomito
r3 = r2 + L_ULNA * np.cos(angle_cum); z3 = z2 + L_ULNA * np.sin(angle_cum)
p3 = np.array([r3 * cos_b, r3 * sin_b, z3])
# P4 (Pinza)
angle_cum_tot = angle_cum + th_polso
r4 = r3 + L_MANO * np.cos(angle_cum_tot); z4 = z3 + L_MANO * np.sin(angle_cum_tot)
p4 = np.array([r4 * cos_b, r4 * sin_b, z4])
return np.array([p0, p1, p2, p3, p4])

# --- 3. LOGICA DI SELEZIONE MODIFICATA ---
def scegli_soluzione_migliore(soluzioni, angoli_precedenti):
if not soluzioni: return None
migliore_sol = None
miglior_punteggio = -np.inf
for sol in soluzioni:
th_spalla = sol[1] # Angolo M2 (Spalla)
deviazione_gomito_rad = abs(sol[2])
# >>> NUOVO VINCOLO FORTE: Z DEL GOMITO POSITIVA <<<
# Z_gomito = L_BASE + L_OMERO * sin(theta_spalla)
z_gomito = L_BASE + L_OMERO * np.sin(th_spalla)
if z_gomito <= 0.01: # Uso 0.01 come margine di sicurezza
# Scarta la soluzione: il gomito è sotto il tavolo o troppo vicino
continue
# Vincolo di flessibilità (Angolo > 90 gradi interni)
score = 0
if deviazione_gomito_rad < np.pi/2:
score += 1000
else:
score -= 1000
# Vincolo di continuità
if angoli_precedenti is not None:
diff = np.linalg.norm(np.array(sol) - np.array(angoli_precedenti))
score -= diff * 100
if score > miglior_punteggio:
miglior_punteggio = score
migliore_sol = sol
return migliore_sol

# --- 4. CONFIGURAZIONE TRAIETTORIA ---
HOME_POS = np.array([0.0, 0.15, 0.25])
START_CIRCLE = np.array([CENTER[0] + RADIUS, CENTER[1], CENTER[2]])

# Generazione Traiettoria (Avvicinamento + Cerchio)
frames_approach = 40
traj_approach_x = np.linspace(HOME_POS[0], START_CIRCLE[0], frames_approach)
traj_approach_y = np.linspace(HOME_POS[1], START_CIRCLE[1], frames_approach)
traj_approach_z = np.linspace(HOME_POS[2], START_CIRCLE[2], frames_approach)

frames_circle = 80
angles = np.linspace(0, 2*np.pi, frames_circle)
traj_circle_x = CENTER[0] + RADIUS * np.cos(angles)
traj_circle_y = CENTER[1] + RADIUS * np.sin(angles)
traj_circle_z = np.full_like(angles, CENTER[2])

full_traj_x = np.concatenate([traj_approach_x, traj_circle_x])
full_traj_y = np.concatenate([traj_approach_y, traj_circle_y])
full_traj_z = np.concatenate([traj_approach_z, traj_circle_z])
TOTAL_FRAMES = len(full_traj_x)

# --- 5. ANIMAZIONE ---
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')
ax.set_xlim(-0.1, 0.3); ax.set_ylim(-0.2, 0.2); ax.set_zlim(0, 0.4) # Aggiornato Y per vedere meglio
ax.set_xlabel('X'); ax.set_ylabel('Y'); ax.set_zlabel('Z')
ax.set_title(f'Tinkerkit Braccio - Z Target={CENTER[2]:.2f}m con Z Gomito > 0')

line_robot, = ax.plot([], [], [], 'o-', lw=4, color='tab:blue', label='Robot')
point_target, = ax.plot([], [], [], 'X', color='red', label='Target')
line_trace, = ax.plot([], [], [], '-', lw=1, color='red', alpha=0.5)

# Aggiunge il piano Z=0
xx, yy = np.meshgrid(np.linspace(-0.1, 0.3, 2), np.linspace(-0.2, 0.2, 2))
ax.plot_surface(xx, yy, np.zeros_like(xx), alpha=0.2, color='gray')

ax.legend()

prev_angles = None
history_x, history_y, history_z = [], [], []

def update(frame_idx):
global prev_angles
tx = full_traj_x[frame_idx]
ty = full_traj_y[frame_idx]
tz = full_traj_z[frame_idx]
sols = ik_braccio(tx, ty, tz, PHI_PITCH, L_BASE, L_OMERO, L_ULNA, L_MANO)
best_sol = scegli_soluzione_migliore(sols, prev_angles)
if best_sol:
prev_angles = best_sol
points = calcola_punti_robot(best_sol)
line_robot.set_data(points[:,0], points[:,1])
line_robot.set_3d_properties(points[:,2])
point_target.set_data([tx], [ty])
point_target.set_3d_properties([tz])
history_x.append(tx); history_y.append(ty); history_z.append(tz)
line_trace.set_data(history_x, history_y)
line_trace.set_3d_properties(history_z)
return line_robot, point_target, line_trace

ani = animation.FuncAnimation(fig, update, frames=TOTAL_FRAMES, interval=40, blit=False, repeat=True)
plt.show()


 

 

Correzione atmosferica su dati EnMap

 Mi e' stato girato un articolo   Detecting rare earth elements using EnMAP hyperspectral satellite data: a case study from Mountain Pas...