domenica 9 novembre 2025

Compilare libreria M5Unified in progetti IDF

Volevo unire un progetto degli esempi dell'SDK IDF con la libreria M5Unified e mi sono accorto che non e' cosi' banale in quanto gli esempi sono scritti in C mentre M5Unified e' in C++


 

Si puo' ovviare creando un wrapper 

 idf.py create-project m5stick_test

 idf.py add-dependency "m5stack/m5unified"

 nel folder main si creano i file m5_wrapper.c e m5_wrapper.h

 m5_wrapper.c

#include <M5Unified.h>
#include "m5_wrapper.h"

extern "C" {
// Initialize M5Unified (C++ side)
void m5_init(void) {
auto cfg = M5.config();
M5.begin(cfg);
}

// Print a C string
void m5_print(const char *text) {
M5.Display.println(text);
}

// Print an integer
void m5_print_int(int value) {
M5.Display.println(value);
}

void m5_set_text_size(int size) {
M5.Display.setTextSize(size);
}

void m5_set_cursor(int x, int y) {
M5.Display.setCursor(x, y);
}

void m5_clear(void) {
M5.Display.clear();
}
}

 m5_wrapper.c

#pragma once

#ifdef __cplusplus
extern "C" {
#endif

void m5_init(void);
void m5_print(const char *text);
void m5_print_int(int value);
void m5_set_text_size(int size);
void m5_set_cursor(int x, int y);
void m5_clear(void);

#ifdef __cplusplus
}
#endif

a questo punto si modifica il file CMakeLists.txt aggiungendo il file m5_wrapper.cpp

CMakeLists.txt 

idf_component_register(SRCS "hid_host_example.c" "m5_wrapper.cpp"
INCLUDE_DIRS "."
PRIV_REQUIRES usb esp_driver_gpio
)


 

nel programma main.c si include l'header

#include "m5_wrapper.h"


 e poi si inizializza

m5_init();


 

idf.py -p /dev/ttyUSB0 -b 115200 flash monitor 

 

 

venerdì 7 novembre 2025

Lettura valori Thrustmaster Ferrari 458 Racing Wheel

 Sarebbe stato troppo funzionasse come questo 


 In realta' questo volante non si presenta come un device HID ma come un dispositivo joystick /dev/input/js0 e si puo' usare il comando


jstest /dev/input/js0

i valori dello sterzo sono sull'asse Z  vanno da 0 (tutto a sinistra) a 65535 (tutto a destra) con il valore centrale quando lo sterzo e' al centro 

 

 

 

giovedì 6 novembre 2025

Tokunaga Trees

 Sempre dal libro del post precedente generazione di alberi frattali con algoritmo di Tokunaga 




import random
import matplotlib.pyplot as plt
import numpy as np

# --- 1. CLASSE DATI (Ramo) ---
class Ramo:
"""Rappresenta un segmento con il suo Ordine di Strahler."""
def __init__(self, ordine, nome=None):
self.ordine = ordine
self.nome = nome if nome else f"Ramo-{ordine}"
self.affluenti = []
# Dati per la visualizzazione (inizializzati durante la generazione)
self.x1, self.y1 = 0, 0
self.x2, self.y2 = 0, 0
self.spessore = 1.0

def aggiungi_affluente(self, ramo):
self.affluenti.append(ramo)

# --- 2. LOGICA DI GENERAZIONE E VISUALIZZAZIONE ---

def genera_tokunaga_tree_ricorsivo(
ordine_corrente,
ordine_max,
a, c,
x_start, y_start,
angolo_base,
lunghezza_base
):
"""
Genera un Tokunaga Tree ricorsivamente e calcola le coordinate per la stampa.
"""
# Calcola le coordinate finali
angolo_rad = np.deg2rad(angolo_base)
x_end = x_start + lunghezza_base * np.cos(angolo_rad)
y_end = y_start + lunghezza_base * np.sin(angolo_rad)
# Crea il nodo Ramo
ramo_principale = Ramo(ordine_corrente)
ramo_principale.x1, ramo_principale.y1 = x_start, y_start
ramo_principale.x2, ramo_principale.y2 = x_end, y_end
# Lo spessore è proporzionale all'ordine (per l'estetica)
ramo_principale.spessore = ordine_corrente * 0.5

# 1. Caso Base: Se l'ordine è 1, non ha affluenti ricorsivi.
if ordine_corrente == 1:
ramo_principale.nome = "Sorgente"
return ramo_principale
# 2. Affluente Principale (di ordine i-1)
# L'affluente principale continua nella stessa direzione con un ordine inferiore.
# Calcolo lunghezza e angoli per il prossimo livello
lunghezza_successiva = lunghezza_base * 0.7 # Riduzione della lunghezza
angolo_deviazione = 20 # Angolo massimo di deviazione
# L'affluente principale si unisce alla fine (x_end, y_end)
affluente_principale = genera_tokunaga_tree_ricorsivo(
ordine_corrente - 1, ordine_max, a, c,
x_end, y_end,
angolo_base + random.uniform(-1, 1) * 5, # Leggera variazione
lunghezza_successiva
)
ramo_principale.aggiungi_affluente(affluente_principale)

# 3. Affluenti Laterali (Side Branching) secondo la regola di Tokunaga
for i in range(1, ordine_corrente - 1): # L'ordine i è sempre < ordine_corrente - 1
k = ordine_corrente - i
# Tokunaga: T_k = a * c^(k-1)
num_medio_affluenti = a * (c ** (k - 1)) if k >= 1 else 0
# Determinazione del numero di affluenti laterali da aggiungere (in modo casuale)
num_affluenti = int(num_medio_affluenti)
if random.random() < (num_medio_affluenti % 1):
num_affluenti += 1
for n in range(num_affluenti):
# Posizione di giunzione: lungo il ramo principale (casualizzata)
t = random.uniform(0.2, 0.8) # Tra il 20% e l'80% della lunghezza
x_affluente_start = x_start + t * (x_end - x_start)
y_affluente_start = y_start + t * (y_end - y_start)

# Angolo dell'affluente laterale
deviazione_laterale = random.choice([1, -1]) * random.uniform(25, 45)
angolo_affluente = angolo_base + deviazione_laterale
affluente_laterale = genera_tokunaga_tree_ricorsivo(
i, ordine_max, a, c,
x_affluente_start, y_affluente_start,
angolo_affluente,
lunghezza_successiva * 0.8 # Sono un po' più corti
)
ramo_principale.aggiungi_affluente(affluente_laterale)
return ramo_principale


def disegna_albero(ramo, ax):
"""Disegna ricorsivamente il ramo e tutti i suoi affluenti."""
# Disegna il ramo corrente
line, = ax.plot(
[ramo.x1, ramo.x2],
[ramo.y1, ramo.y2],
color='blue',
linewidth=ramo.spessore,
alpha=0.8
)

# Chiama ricorsivamente per gli affluenti
for affluente in ramo.affluenti:
disegna_albero(affluente, ax)

# --- 3. ESECUZIONE E PLOT ---

# Parametri del Critical Tokunaga Model (adattati per la visualizzazione)
A_PARAM = 1.3
C_PARAM = 2.3
ORDINE_FINALE = 5
LUNGHEZZA_INIZIALE = 10.0

# Punti di partenza (alla base del plot) e direzione (verso l'alto)
X_START, Y_START = 0, -10
ANGOLO_INIZIALE = 90

# Generazione dell'albero
albero_radice = genera_tokunaga_tree_ricorsivo(
ORDINE_FINALE, ORDINE_FINALE,
A_PARAM, C_PARAM,
X_START, Y_START,
ANGOLO_INIZIALE,
LUNGHEZZA_INIZIALE
)

# Configurazione del Plot Matplotlib
fig, ax = plt.subplots(figsize=(8, 8))
ax.set_title(f"Tokunaga Tree (Ordine Max={ORDINE_FINALE}, a={A_PARAM}, c={C_PARAM})")
ax.set_aspect('equal', adjustable='box')
ax.axis('off') # Nasconde gli assi

# Disegno dell'albero
disegna_albero(albero_radice, ax)

# Imposta i limiti per vedere bene tutto l'albero
ax.set_xlim(-20, 20)
ax.set_ylim(-15, 20)

plt.show()

Diffusion Limited Aggregation

 Sto leggendo  Fractals and Chaos in Geology and Geophysics 2nd edition -- Donald Lawson Turcotte -- 2nd ed_, Cambridge, U_K, New York, England, 1997 

Molto interessante anche se un po' e' passato di moda come argomento (se ne parlava molto a cavallo anni 90/00). Questo tipo di frattali che assomiglia agli ossidi di manganese nelle fratture delle rocce sono comunque affascinanti

 

https://thumbs.dreamstime.com/b/minerali-dentritici-degli-ossidi-del-manganese-e-del-ferro-71827942.jpg

 

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

class DLA:
def __init__(self, size=400, num_particles=3000):
self.size = size
self.num_particles = num_particles
self.grid = np.zeros((size, size), dtype=bool)
self.center = size // 2
# Start with seed particle at center
self.grid[self.center, self.center] = True
# Store occupied positions for neighbor checking
self.occupied = {(self.center, self.center)}
# Maximum radius for spawning particles
self.spawn_radius = 10
self.max_radius = self.spawn_radius
def get_neighbors(self, x, y):
"""Get 4-connected neighbors"""
neighbors = []
for dx, dy in [(0, 1), (1, 0), (0, -1), (-1, 0)]:
nx, ny = x + dx, y + dy
if 0 <= nx < self.size and 0 <= ny < self.size:
neighbors.append((nx, ny))
return neighbors
def is_adjacent_to_cluster(self, x, y):
"""Check if position is adjacent to existing cluster"""
for nx, ny in self.get_neighbors(x, y):
if (nx, ny) in self.occupied:
return True
return False
def random_walk_step(self, x, y):
"""Perform one random walk step"""
direction = np.random.randint(0, 4)
if direction == 0 and y < self.size - 1:
y += 1
elif direction == 1 and x < self.size - 1:
x += 1
elif direction == 2 and y > 0:
y -= 1
elif direction == 3 and x > 0:
x -= 1
return x, y
def spawn_particle(self):
"""Spawn particle at random position on circle around cluster"""
angle = np.random.uniform(0, 2 * np.pi)
r = self.spawn_radius
x = int(self.center + r * np.cos(angle))
y = int(self.center + r * np.sin(angle))
# Clamp to grid boundaries
x = np.clip(x, 0, self.size - 1)
y = np.clip(y, 0, self.size - 1)
return x, y
def add_particle(self):
"""Add one particle via random walk"""
x, y = self.spawn_particle()
max_steps = 100000
steps = 0
while steps < max_steps:
# Check if adjacent to cluster
if self.is_adjacent_to_cluster(x, y):
self.grid[x, y] = True
self.occupied.add((x, y))
# Update spawn radius
dist = np.sqrt((x - self.center)**2 + (y - self.center)**2)
if dist > self.max_radius:
self.max_radius = dist
self.spawn_radius = int(dist + 10)
return True
# Random walk
x, y = self.random_walk_step(x, y)
# If particle wanders too far, respawn
dist = np.sqrt((x - self.center)**2 + (y - self.center)**2)
if dist > self.spawn_radius + 20:
x, y = self.spawn_particle()
steps += 1
return False
def grow(self):
"""Grow the aggregate"""
for i in range(self.num_particles):
self.add_particle()
if (i + 1) % 100 == 0:
print(f"Added {i + 1}/{self.num_particles} particles")
def visualize(self):
"""Display the final aggregate"""
fig, ax = plt.subplots(figsize=(10, 10))
ax.imshow(self.grid, cmap='hot', interpolation='nearest')
ax.set_title(f'Diffusion Limited Aggregation\n{self.num_particles} particles')
ax.axis('off')
plt.tight_layout()
plt.show()

# Run simulation
print("Starting DLA simulation...")
dla = DLA(size=400, num_particles=3000)
dla.grow()
print("Simulation complete! Displaying result...")
dla.visualize()

Ros Noetic Docker Phantomx Reactor Robotic Arm

Ci avevo provato qui ma non era andato bene (solo Arduino era ok)..ci riprovo adesso con il dispositivo fisico 

 

  

 

Attenzione: la scheda Arbotix deve essere gia' montato lo sketch ROS (vedi post precedente)

Per prima cosa si crea nella propria home

mkdir ~/ws_catkin

mkdir ~/ws_catkin/src 

xhost +local:docker

poi si lancia il docker (immagine completa di No Etic) 

sudo docker run -it   --net=host   --env="DISPLAY=$DISPLAY"   --env="QT_X11_NO_MITSHM=1"   --env="XAUTHORITY=$XAUTH"   --volume="/tmp/.X11-unix:/tmp/.X11-unix:rw"   --volume="$HOME/ws_catkin:/root/ws_catkin:rw" --device=/dev/ttyUSB0:/dev/ttyUSB0 --privileged   --name ros_noetic_gui   osrf/ros:noetic-desktop-full

per testare si usa il simulatore turtle  

roscore&

rosrun turtlesim turtlesim_node&
 
si dovrebbe essere aperta una finestra grafica 

 
si richiedono i servizi disponibili
rosservice list
 
/turtle1/set_pen
/turtle1/teleport_absolute
/turtle1/teleport_relative
/turtlesim/get_loggers
/turtlesim/set_logger_level
 
ed i topic 
rostopic list
 
/rosout
/rosout_agg
/turtle1/cmd_vel
/turtle1/color_sensor
/turtle1/pose

 
si richiedono le info su un topic  
rostopic info /turtle1/cmd_vel 
 
Type: geometry_msgs/Twist
Publishers: None
Subscribers:
/turtlesim (http://...)



ed il formato dei messaggi
rosmsg show geometry_msgs/Twist
geometry_msgs/Vector3 linear
  float64 x
  float64 y
  float64 z
geometry_msgs/Vector3 angular
  float64 x
  float64 y
  float64 z



a questo punto si puo' muovere la tartaruga
rostopic pub /turtle1/cmd_vel geometry_msgs/Twist "{linear: {x: 3.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 2.0}}"
 
per lo spostamento assoluto 
rosservice call /turtle1/teleport_absolute 5 5 0

si puo' pilotare la tartaruga anche la pressione dei tasti usando  
rosrun turtlesim turtle_teleop_key 
 
a questo punto si inizia a modificare il container per impostarlo sul Phantomx Reactor 
sudo apt update
sudo apt install udev python3-serial 
 
a questo punto si inizia a preparare l'ambiente  ROS per il braccio robotico
 
cd /root/ws_catkin/src 
git clone https://github.com/vanadiumlabs/arbotix_ros.git
git clone https://github.com/RobotnikAutomation/phantomx_reactor_arm
git clone https://github.com/arebgun/dynamixel_motor.git
cd ..
 
i file su Github sono fatti per Python 2.7 mentre Ros NoEtic usa Python3 ...delle due l'una ... o si installa python2.7 o si modificano i files 
 
 
cd ~/ws_catkin/src/phantomx_reactor_arm/phantomx_reactor_arm_controller/src


sed -i '1s|/usr/bin/env python|/usr/bin/env python3|' *.py

chmod +x *.py
 
sed -i 's/except rospy\.ROSException, e:/except rospy.ROSException as e:/' phantomx_reactor_parallel_motor_joints.py
 
 
catkin_make
source devel/setup.bash
rospack profile
  
 
0.023993   /opt/ros/noetic/share
0.002395   /root/ws_catkin/src
0.000854   /root/ws_catkin/src/arbotix_ros
0.000626   /root/ws_catkin/src/dynamixel_motor
0.000614   /root/ws_catkin/src/phantomx_reactor_arm

se tutto va bene 
rospack list | grep arbotix
arbotix_controllers /root/ws_catkin/src/arbotix_ros/arbotix_controllers
arbotix_firmware /root/ws_catkin/src/arbotix_ros/arbotix_firmware
arbotix_msgs /root/ws_catkin/src/arbotix_ros/arbotix_msgs
arbotix_python /root/ws_catkin/src/arbotix_ros/arbotix_python
arbotix_sensors /root/ws_catkin/src/arbotix_ros/arbotix_sensors
rospack list | grep phantomx
phantomx_reactor_arm_controller /root/ws_catkin/src/phantomx_reactor_arm/phantomx_reactor_arm_controller
phantomx_reactor_arm_description /root/ws_catkin/src/phantomx_reactor_arm/phantomx_reactor_arm_description
phantomx_reactor_arm_moveit_config /root/ws_catkin/src/phantomx_reactor_arm/phantomx_reactor_arm_moveit_config


si prepara la porta USB
sudo cp phantomx_reactor_arm/phantomx_reactor_arm_controller/config/57-reactor_arbotix.rules /etc/udev/rules.d/
 
lanciare il comando 
udevadm info -a -n /dev/ttyUSB0 | grep serial
che risponde 
ATTRS{serial}=="AH06H0KT"

e quindi
sudo nano /etc/udev/rules.d/99-reactor.rules
e si copia 
SUBSYSTEM=="tty", ATTRS{serial}=="AH06H0KT", SYMLINK+="ttyUSB_REACTOR"

si aggiorna udev 
sudo service udev reload
sudo service udev restart
sudo udevadm trigger 

se persistono problemi (ovvero che non viene vista la porta USB_REACTOR) puo' essere forzata con 
 
ln -s /dev/ttyUSB0 /dev/ttyUSB_REACTOR

quasi pronti...si dovrebbe lanciare il comando 

roslaunch phantomx_reactor_arm_controller arbotix_phantomx_reactor_arm_wrist.launch&
 
a questo punto si possono testare le stringhe comando
 
 
rostopic pub /phantomx_reactor_controller/shoulder_yaw_joint/command std_msgs/Float64 "data: 0.0"
rostopic pub /phantomx_reactor_controller/shoulder_pitch_joint/command std_msgs/Float64 "data: 0.0"
rostopic pub /phantomx_reactor_controller/elbow_pitch_joint/command std_msgs/Float64 "data: 0.0"
rostopic pub /phantomx_reactor_controller/wrist_yaw_joint/command std_msgs/Float64 "data: 0.0"
rostopic pub /phantomx_reactor_controller/wrist_pitch_joint/command std_msgs/Float64 "data: 0.0"
rostopic pub /phantomx_reactor_controller/gripper_revolute_joint/command std_msgs/Float64 "data: 0.0"
rostopic pub /phantomx_reactor_controller/gripper_prismatic_joint/command std_msgs/Float64 "data: 0.0"
 
i valori sono espressi tutti in radianti e sono valori assoluti
per spostarsi dalla posizione neutra al +90 gradi si immette data:1.57, per tornare indietro di immette data:0.0 e NON data:-1.57 

Per impostare la velocita' (espressa in rad/s)
rosparam set /arbotix/joints/shoulder_yaw_joint/max_speed 0.5
 
 
 
Oltre ad usare il braccio si puo' usare l'emulazione ma si devono fare delle modifiche
nano ~/ws_catkin/src/phantomx_reactor_arm/phantomx_reactor_arm_moveit_config/launch/planning_context.launch

e si modifica la linea cambiando xacro.py a xacro
 
 <param if="$(arg load_robot_description)" name="$(arg robot_description)" command="$(find xacro)/xacro '$(find phantomx_reactor_arm_description)/robots/phantomx_reactor_arm_wrist.urdf.xacro'"/>

sudo apt update
sudo apt install ros-noetic-moveit
export RVIZ_PLUGIN_PATH=/opt/ros/noetic/lib


e si ricompila il ws_catkin

roslaunch phantomx_reactor_arm_moveit_config demo.launch

visto tutto il lavoro fatto e' il caso di salvare le impostazione tramite commit
si apre una nuova shell e si lancia
docker ps -a
si legge l'id e si lancia
 
docker commit b8a109b1fd3b braccio_robotico:latest
 
per riaprire 
docker run -it --net=host braccio_robotico:latest

si ricorda che ad ogni nuovo riavvio si deve lanciare 
source ~/ws_catkin/devel/setup.bash

rosservice list
/arbotix/SetupAnalogIn
/arbotix/SetupDigitalIn
/arbotix/SetupDigitalOut
/arbotix/get_loggers
/arbotix/set_logger_level
/elbow_pitch_joint/enable
/elbow_pitch_joint/relax
/elbow_pitch_joint/set_speed
/elbow_pitch_mimic_joint/enable
/elbow_pitch_mimic_joint/relax
/elbow_pitch_mimic_joint/set_speed
/gripper_revolute_joint/enable
/gripper_revolute_joint/relax
/gripper_revolute_joint/set_speed
/move_group/get_loggers
/move_group/planning_scene_monitor/set_parameters
/move_group/set_logger_level
/phantomx_reactor_controller/get_loggers
/phantomx_reactor_controller/set_logger_level
/phantomx_reactor_parallel_gripper/get_loggers
/phantomx_reactor_parallel_gripper/set_logger_level
/robot_state_publisher/get_loggers
/robot_state_publisher/set_logger_level
/rosout/get_loggers
/rosout/set_logger_level
/servos/enable_all
/servos/relax_all
/shoulder_pitch_joint/enable
/shoulder_pitch_joint/relax
/shoulder_pitch_joint/set_speed
/shoulder_pitch_mimic_joint/enable
/shoulder_pitch_mimic_joint/relax
/shoulder_pitch_mimic_joint/set_speed
/shoulder_yaw_joint/enable
/shoulder_yaw_joint/relax
/shoulder_yaw_joint/set_speed
/wrist_pitch_joint/enable
/wrist_pitch_joint/relax
/wrist_pitch_joint/set_speed
/wrist_roll_joint/enable
/wrist_roll_joint/relax
/wrist_roll_joint/set_speed
 
topics
/diagnostics
/elbow_pitch_joint/command
/elbow_pitch_mimic_joint/command
/gripper_revolute_joint/command
/joint_states
/move_group/planning_scene_monitor/parameter_descriptions
/move_group/planning_scene_monitor/parameter_updates
/phantomx_reactor_controller/elbow_pitch_joint/command
/phantomx_reactor_controller/gripper_prismatic_joint/command
/phantomx_reactor_controller/gripper_revolute_joint/command
/phantomx_reactor_controller/joint_command
/phantomx_reactor_controller/shoulder_pitch_joint/command
/phantomx_reactor_controller/shoulder_yaw_joint/command
/phantomx_reactor_controller/wrist_pitch_joint/command
/phantomx_reactor_controller/wrist_roll_joint/command
/rosout
/rosout_agg
/shoulder_pitch_joint/command
/shoulder_pitch_mimic_joint/command
/shoulder_yaw_joint/command
/tf
/tf_static
/wrist_pitch_joint/command
/wrist_roll_joint/command
 
 
per abilitare un asse
 

rosservice call /elbow_pitch_joint/enable "data: true"

 rostopic echo /joint_states

 

Lettura valori volante Logitech G920

In questo post ho voluto provare a leggere i valori in uscita da un Logitech G920 Racing Wheel  


 

il volante si presenta in USB con ID 046d:c262  ed e' un dispositivo HID

Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 002: ID 1199:9079 Sierra Wireless, Inc. EM7455
Bus 001 Device 003: ID 8087:0a2b Intel Corp. Bluetooth wireless interface
Bus 001 Device 004: ID 04ca:7066 Lite-On Technology Corp. Integrated Camera
Bus 001 Device 006: ID 046d:c262 Logitech, Inc. G920 Driving Force Racing Wheel
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub

Per leggere i messaggi HID si puo' semplicemente lancia

luca@nemo:~$ sudo usbhid-dump -d 046d:c262 -e all  

CC001:012:000:DESCRIPTOR         1762351342.982709
 05 01 09 04 A1 01 A1 02 85 01 15 00 25 07 35 00
 46 3B 01 65 14 09 39 75 04 95 01 81 42 65 00 25
 01 45 01 05 09 19 01 29 12 75 01 95 12 81 02 95
 02 81 01 27 FF FF 00 00 47 FF FF 00 00 05 01 09
 30 75 10 95 01 81 02 26 FF 00 46 FF 00 09 31 09
 32 09 35 75 08 95 03 81 02 25 01 45 01 06 09 FF
 19 01 29 03 75 01 95 03 81 02 95 05 81 01 C0 C0
 06 43 FF 0A 02 06 A1 01 85 11 75 08 95 13 15 00
 26 FF 00 09 02 81 00 09 02 91 00 C0 06 43 FF 0A
 04 06 A1 01 85 12 75 08 95 3F 15 00 26 FF 00 09
 04 81 00 09 04 91 00 C0

001:012:000:STREAM             1762351342.991209
 01 0F 00 00 11 80 FF FF FF 07

001:012:000:STREAM             1762351344.926453
 01 0F 00 00 11 80 F1 FF FF 07

001:012:000:STREAM             1762351344.936386
 01 0F 00 00 11 80 DD FF FF 07

001:012:000:STREAM             1762351344.946409
 01 0F 00 00 11 80 C5 FF FF 07

come si vede i messaggi hanno 10 byte (almeno nella versione PC/XBox che possiedo)

i valori della rotazione del volante sono nei byte 5 e 6 sono big endian e vanno da 0 con il volante tutto a sinistra (rotazione di 450 gradi a sinistra) a 65535 con il volante tutto a destra (rotazione di 450 gradi a destra). La posizione neutra e'  32789 (almeno nella mia calibrazione)

echo $(( 0x$f6 * 256 + 0x$f5 )) 

il valore dell'acceleratore sul byte 7 con valore FF a pedale rialzato

il valore del freno e' sul byte 8 con valore FF a freno rilasciato

 

venerdì 31 ottobre 2025

Caricamento progressivo di cloudpoints and meshes

In caso di nuvole di punti o mesh molto numerose puo' essere molto lento il caricamento di tutto il tema via interfaccia web ed esiste la possibilita' di fare caricamenti progressivi basati sulla distanza del punto di vista...in questo caso pero' i dati devono essere preparati in modo idoneo 

POINTCLOUD

git clone https://github.com/potree/PotreeConverter.git

cd PotreeConverter

mkdir build && cd build

cmake ..

make -j4

./PotreeConverter /path/to/input.ply -o /path/to/output/
(funziona anche con i Laz)


MESH

# Clone the main gltfpack repository

git clone https://github.com/zeux/meshoptimizer.git gltfpack_source

cd gltfpack_source


# Clone the required basis_universal fork (for KHR_texture_basisu support)

git clone -b gltfpack https://github.com/zeux/basis_universal basis_universal


# Clone libwebp (for WebP support)

git clone https://github.com/webmproject/libwebp libwebp

ABSOLUTE_PATH_ROOT=$(pwd)/..


cmake .. \

    -DMESHOPT_BUILD_GLTFPACK=ON \

    -DMESHOPT_GLTFPACK_BASISU_PATH="${ABSOLUTE_PATH_ROOT}/basis_universal" \

    -DMESHOPT_GLTFPACK_LIBWEBP_PATH="${ABSOLUTE_PATH_ROOT}/libwebp"


make

make install

gltfpack -i model.glb -o model_lods.glb -cc -tc -si 0.5 -si 0.25 -si 0.1



Analisi MNF su spettri di riflettanza di plastica

Devo cerca di lavorare su spettri di riflettanza di plastica e la prima domanda e': quale sono le bande significative? Sono partito dal ...