Questo modello di Pong Soundic anno 1979 a colori lo ho comprato come rotto in quanto i controller non rispondevano
Di fatto pero' i controller sono dei semplici potenziometri
Questo modello di Pong Soundic anno 1979 a colori lo ho comprato come rotto in quanto i controller non rispondevano
Di fatto pero' i controller sono dei semplici potenziometri
Per misurare le lunghezze e gli angoli di una nuvola di punti su CloudCompare si clicchi sul pulsante cerchiato in rosso nell'immagine successiva
Ho ritirato fuori il mio tablet Google Yellowstone Tango per provare il trattamento dati delle nuvole dei punti con PCL
I dati reali sono stati presi presso la cava di Maiano (Fiesole) che e' la palestra di geologia per numerose generazioni di geologi fiorentini
Ho ripreso con lo scanner del tablet questo dettaglio
in particolare volevo vedere se riuscivo a misurare l'angolo tra i due piani indicati nella foto sottostante
(quello in blu e' il piano del fronte di scavo, quello in rosso e' relativo ad una frattura)
Usando la app Clino Fieldmove e Innstereo
a posteriori la scelta delle superfici non e' stata felicissima perche' sono tutte ad alto angolo e si distinguono poco sullo stereoplot
Con il tablet la distanza massima a cui era possibile avere risposta dallo scanner era di circa 3 m. Per prova la superficie e' stata bagnata per vedere se il laser infrarosso era influenzato dall'umidita' della parete ma non si verifiche significative tra superficie asciutta e bagnata
I dati sono stati salvati in PLY e sono stati elaborati con PCL in QtCreator
Il programma dopo aver caricato il file PLY fa un sottocampionamento dei dati con VoxelGrid (passando da oltre 200.000 superfici a poco oltre 50 superfici) e calcola le normali. I dati sono visualizzati con il visualizzatore interno a PLC
leggermente modificato da https://github.com/jeffdelmerico/pointcloud_tutorial
========================================
cmake_minimum_required(VERSION 3.5)
project(maiano LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(PCL 1.3 REQUIRED COMPONENTS common io features visualization)
include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS})
add_definitions(${PCL_DEFINITIONS})
add_executable(maiano main.cpp)
target_link_libraries(maiano ${PCL_LIBRARIES})
========================================
#include <iostream>
#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
#include <pcl/io/ply_io.h>
#include <pcl/io/pcd_io.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/kdtree/kdtree_flann.h>
#include <pcl/features/normal_3d.h>
#include <pcl/visualization/pcl_visualizer.h>
using namespace std;
void
downsample (pcl::PointCloud<pcl::PointXYZRGB>::Ptr &points, float leaf_size,
pcl::PointCloud<pcl::PointXYZRGB>::Ptr &downsampled_out)
{
cout << "PointCloud before filtering: " << points->width * points->height
<< " data points (" << pcl::getFieldsList (*points) << ")." << std::endl;
pcl::VoxelGrid<pcl::PointXYZRGB> vox_grid;
vox_grid.setLeafSize (leaf_size, leaf_size, leaf_size);
vox_grid.setInputCloud (points);
vox_grid.filter (*downsampled_out);
cout << "PointCloud after filtering: " << downsampled_out->width * downsampled_out->height
<< " data points (" << pcl::getFieldsList (*downsampled_out) << ")." << std::endl;
}
void compute_surface_normals (pcl::PointCloud<pcl::PointXYZRGB>::Ptr &points, float normal_radius,
pcl::PointCloud<pcl::Normal>::Ptr &normals_out)
{
pcl::NormalEstimation<pcl::PointXYZRGB, pcl::Normal> norm_est;
// Use a FLANN-based KdTree to perform neighborhood searches
norm_est.setSearchMethod (pcl::search::KdTree<pcl::PointXYZRGB>::Ptr
(new pcl::search::KdTree<pcl::PointXYZRGB>));
// Specify the size of the local neighborhood to use when computing the surface normals
norm_est.setRadiusSearch (normal_radius);
// Set the input points
norm_est.setInputCloud (points);
// Estimate the surface normals and store the result in "normals_out"
norm_est.compute (*normals_out);
}
void visualize_normals (const pcl::PointCloud<pcl::PointXYZRGB>::Ptr points,
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr normal_points,
const pcl::PointCloud<pcl::Normal>::Ptr normals)
{
// Add the points and normals to the vizualizer
pcl::visualization::PCLVisualizer viz;
viz.addPointCloud (points, "points");
viz.addPointCloud (normal_points, "normal_points");
viz.addPointCloudNormals<pcl::PointXYZRGB, pcl::Normal> (normal_points, normals, 1, 0.01, "normals");
// Give control over to the visualizer
viz.spin ();
}
int main (int argc, char** argv)
{
// Load data from pcd
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZRGB>);
//if (pcl::io::loadPCDFile<pcl::PointXYZRGB> ("../data/robot1.pcd", *cloud) == -1) //* load the file
if (pcl::io::loadPLYFile<pcl::PointXYZRGB> ("maiano.ply", *cloud) == -1) //* load the file
{
PCL_ERROR ("Couldn't read file robot1.pcd \n");
return (-1);
}
// Point Clouds to hold output
pcl::PointCloud<pcl::PointXYZRGB>::Ptr downsampled (new pcl::PointCloud<pcl::PointXYZRGB>);
pcl::PointCloud<pcl::Normal>::Ptr normals (new pcl::PointCloud<pcl::Normal>);
// Downsample the cloud
const float voxel_grid_leaf_size = 1.0;
downsample (cloud, voxel_grid_leaf_size, downsampled);
// Compute surface normals
const float normal_radius = 1.0;
compute_surface_normals (downsampled, normal_radius, normals);
visualize_normals(cloud, downsampled, normals);
int i = 0;
for (pcl::Normal n : *normals) {
std::cout << n.normal_x << "," << n.normal_y << "," << n.normal_z <<"\n";
i++;
}
return(0);
}
========================================
Plottando le normali si ha questo risultato
Al di la' dell'orientamento verso il Nord (che lo scanner non registra in quanto non calibra i dati con la bussola) il programma estra sia le suprfici ad alto angolo che alcun suborizzontali.. non so quanto i dati alla fine siano corretti....i dati delle normali vengono forniti come componenti x,y,z di un versore con origine 0,0,0....non so se ho fatto qualche sbaglio nella conversione in strike e dip
Un progetto molto interessante che sto provando e' GNSS-SDR , un sistema per usare un modulo RTL-SDR v3 da circa 20 ed una antenna GPS da 5 euro per poter ricevere i dati GPS ed utilizzarli per la correzione differenziale (ovviamente il dispositivo agisce come se fosse in banda L1.. per avere la banda L2 bisognerebbe avere un'altra RTL-SDR sintonizzata sulla frequenza L2 ....ed in ogni caso il software non prevede questa decodifica)
Il computer puo' essere un comune portatile...l'unico problema e' che il programma apre un thread per ogni satellite osservato quindi la memoria e' sempre benvenuta
Oltre alla libreria si devono scaricare anche
http://www.rtklib.com/rtklib.htm
https://github.com/rtlsdrblog/rtl-sdr/releases/tag/v1.1
Per far funzionare il software prima si devono configurare i driver della scheda, lanciare il file bat bias_tee_on e successivamente gnss-sdrgui
(il bias tee e' un circuito inserito nell'elettronica dell'RTL-SDR per alimentare l'antenna attiva esterna patch)
Istruzioni nel video
Questa e' la configurazione che ha funzionato per me
% program : RTKPOST ver.2.4.3 b33
% inp file : C:\Users\lucai\Desktop\gpssdr\sdr_20201015113400.obs
% inp file : C:\Users\lucai\Desktop\gpssdr\cal\cala289h00.rnx\cala289h00.20o
% inp file : C:\Users\lucai\Desktop\gpssdr\cal\cala289h00.rnx\cala289h00.20n
% obs start : 2020/10/15 11:34:36.1 GPST (week2127 387276.1s)
% obs end : 2020/10/15 11:44:20.1 GPST (week2127 387860.1s)
% pos mode : static
% freqs : L1+L2
% solution : forward
% elev mask : 15.0 deg
% dynamics : off
% tidecorr : off
% ionos opt : broadcast
% tropo opt : saastamoinen
% ephemeris : broadcast
% amb res : continuous
% val thres : 3.0
% antenna1 : ( 0.0000 0.0000 0.0000)
% antenna2 : ( 0.0000 0.0000 0.0000)
% ref pos : 43.854470000 11.166080000 -50.0000
%
% (lat/lon/height=WGS84/ellipsoidal,Q=1:fix,2:float,3:sbas,4:dgps,5:single,6:ppp,ns=# of satellites)
% GPST latitude(deg) longitude(deg) height(m) Q ns sdn(m) sde(m) sdu(m) sdne(m) sdeu(m) sdun(m) age(s) ratio
2020/10/15 11:36:42.068 43.745316827 11.292427977 -63.6904 2 6 1.0450 0.1566 0.2377 -0.3671 0.0280 0.0864 0.07 1.8
2020/10/15 11:36:48.068 43.745347458 11.292425620 -64.6534 2 6 0.4222 0.1009 0.2274 -0.1555 0.0559 -0.1237 0.07 1.5
2020/10/15 11:36:57.068 43.745340452 11.292424419 -65.2242 2 6 0.3162 0.0907 0.2193 -0.1200 0.0539 -0.1264 0.07 1.1
2020/10/15 11:37:03.068 43.745306097 11.292430701 -65.7996 1 6 0.0136 0.0063 0.0206 -0.0056 0.0036 -0.0125 0.07 3.6
2020/10/15 11:37:09.068 43.745293252 11.292432728 -66.0801 2 6 0.2346 0.0797 0.2056 -0.0921 0.0490 -0.1221 0.07 1.1
2020/10/15 11:37:15.068 43.745286998 11.292432314 -66.6728 2 6 0.2129 0.0759 0.1997 -0.0845 0.0468 -0.1193 0.07 1.2
2020/10/15 11:37:21.068 43.745275726 11.292432226 -66.5496 2 6 0.1968 0.0726 0.1943 -0.0787 0.0449 -0.1166 0.07 1.3
2020/10/15 11:37:27.068 43.745263392 11.292434190 -66.5540 2 6 0.1841 0.0698 0.1893 -0.0741 0.0432 -0.1139 0.07 2.3
2020/10/15 11:37:33.068 43.745263939 11.292432314 -65.8761 2 6 0.1737 0.0673 0.1847 -0.0703 0.0417 -0.1114 0.07 1.9
2020/10/15 11:37:39.068 43.745263809 11.292432072 -65.3947 2 6 0.1651 0.0651 0.1804 -0.0670 0.0403 -0.1090 0.07 1.1
2020/10/15 11:37:45.068 43.745260600 11.292432193 -64.7574 2 6 0.1577 0.0631 0.1764 -0.0642 0.0390 -0.1068 0.07 1.2
2020/10/15 11:37:51.068 43.745257360 11.292431499 -64.6951 2 6 0.1513 0.0613 0.1727 -0.0618 0.0379 -0.1047 0.07 2.2
2020/10/15 11:37:57.068 43.745257344 11.292430153 -64.7047 2 6 0.1457 0.0596 0.1691 -0.0596 0.0369 -0.1027 0.07 1.0
2020/10/15 11:38:03.068 43.745249007 11.292431368 -64.0611 2 6 0.1408 0.0580 0.1658 -0.0577 0.0359 -0.1008 0.07 1.9
2020/10/15 11:38:09.068 43.745238433 11.292434035 -64.0050 2 6 0.1363 0.0566 0.1627 -0.0560 0.0350 -0.0990 0.07 1.1
2020/10/15 11:38:15.068 43.745230377 11.292436913 -63.8980 2 6 0.1323 0.0553 0.1598 -0.0544 0.0342 -0.0973 0.07 1.2
2020/10/15 11:38:21.068 43.745228652 11.292439258 -63.8676 2 6 0.1286 0.0541 0.1570 -0.0529 0.0335 -0.0957 0.07 1.3
2020/10/15 11:38:27.068 43.745224795 11.292441520 -63.8227 2 6 0.1253 0.0529 0.1543 -0.0516 0.0328 -0.0942 0.07 1.1
2020/10/15 11:38:34.068 43.745218911 11.292444739 -63.9953 2 6 0.1222 0.0518 0.1518 -0.0504 0.0322 -0.0928 0.07 2.3
2020/10/15 11:38:40.068 43.745218438 11.292447546 -64.5331 2 6 0.1194 0.0508 0.1494 -0.0492 0.0316 -0.0914 0.07 1.0
2020/10/15 11:38:46.068 43.745214867 11.292448732 -64.9767 2 6 0.1170 0.0499 0.1471 -0.0484 0.0310 -0.0900 0.07 2.1
2020/10/15 11:38:52.068 43.745207694 11.292451080 -65.1364 2 6 0.1145 0.0490 0.1450 -0.0474 0.0305 -0.0888 0.07 1.6
2020/10/15 11:38:58.068 43.745204558 11.292451150 -65.2057 2 6 0.1122 0.0482 0.1429 -0.0464 0.0300 -0.0876 0.07 1.2
2020/10/15 11:39:04.068 43.745206265 11.292447041 -65.3471 2 6 0.1100 0.0474 0.1409 -0.0456 0.0295 -0.0864 0.07 2.6
2020/10/15 11:39:10.068 43.745204921 11.292445771 -65.5508 2 6 0.1080 0.0466 0.1390 -0.0448 0.0291 -0.0853 0.07 2.3
2020/10/15 11:39:17.068 43.745200520 11.292445390 -65.8156 2 6 0.1064 0.0459 0.1371 -0.0442 0.0286 -0.0842 0.07 1.0
2020/10/15 11:39:25.068 43.745196791 11.292446870 -65.6732 1 6 0.0141 0.0063 0.0205 -0.0059 0.0042 -0.0129 0.07 7.5
2020/10/15 11:39:31.068 43.745192898 11.292447003 -65.8577 2 6 0.1029 0.0446 0.1337 -0.0428 0.0279 -0.0822 0.07 2.2
2020/10/15 11:39:37.068 43.745192144 11.292447887 -65.9236 2 6 0.1012 0.0439 0.1320 -0.0421 0.0276 -0.0813 0.07 1.9
2020/10/15 11:39:43.068 43.745191371 11.292448821 -66.2033 1 6 0.0141 0.0063 0.0205 -0.0059 0.0043 -0.0130 0.07 29.7
2020/10/15 11:39:49.068 43.745193313 11.292449696 -66.5907 2 6 0.0982 0.0427 0.1289 -0.0409 0.0269 -0.0795 0.07 1.1
2020/10/15 11:39:55.068 43.745198138 11.292449984 -67.2350 1 6 0.0142 0.0063 0.0205 -0.0059 0.0043 -0.0130 0.07 3.3
2020/10/15 11:40:01.068 43.745195988 11.292452579 -67.6868 2 6 0.0955 0.0416 0.1260 -0.0398 0.0263 -0.0779 0.07 1.1
2020/10/15 11:40:07.068 43.745194796 11.292453940 -68.0674 2 6 0.0942 0.0411 0.1247 -0.0392 0.0261 -0.0771 0.07 1.5
2020/10/15 11:40:13.068 43.745194622 11.292454531 -68.3254 2 6 0.0930 0.0406 0.1233 -0.0387 0.0258 -0.0763 0.07 1.8
2020/10/15 11:40:19.068 43.745194780 11.292455399 -68.2927 1 6 0.0142 0.0063 0.0205 -0.0060 0.0044 -0.0131 0.07 7.1
2020/10/15 11:40:25.068 43.745198122 11.292453471 -67.9572 2 6 0.0907 0.0396 0.1208 -0.0378 0.0253 -0.0749 0.07 2.3
2020/10/15 11:40:31.068 43.745200144 11.292452410 -67.7198 1 6 0.0143 0.0063 0.0205 -0.0060 0.0045 -0.0131 0.07 6.3
Vista la necessita' di plottare in uno scatterplot 3D qualche decina di migliaia di punti ho cercato una libreria adeguata e l'ho trovata in Matplot++
add_subdirectory(matplotplusplus)
add_executable(grafico
main.cpp
)
target_link_libraries(grafico PUBLIC matplot Qt${QT_VERSION_MAJOR}::Core)
#target_link_libraries(grafico PUBLIC matplot)
per la visualizzazione e' necessario che sia installato gnuplot
Per provare l'ebbrezza di un calcolatore libero sia dal punto di vista hardware che software da materiale proprietario mi sono comprato un Lenovo T400 con il Bios modificato e sostituito con Coreboot e con Trisquel come sistema operativo
Con l'arrivo del sensore lidar sugli IPhone (rip Project Tango) forse e' il caso di ritirare fuori le librerie per trattare le nuvole di punti come PCL
Per installare la liberia su Debian e' sufficiente
apt-get install libpcl-dev
che si porta dietro un po' di dipendenze come boost
I primi passi sono ovviamente quelli di inserire la libreria in un progetto. Per questo sono partito da QTCreator con le varie opzioni di Make
Compilazione con CMake
per la compilazione si devono aggiungere le righe in giallo al file CMakeLists.txt. Attenzione che in PCL le funzioni sono distribuite in vari moduli che devono essere specificati in REQUIRED COMPONENTS
cmake_minimum_required(VERSION 3.5)
project(nuvola LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(PCL 1.3 REQUIRED COMPONENTS common io features)
include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS})
add_definitions(${PCL_DEFINITIONS})
add_executable(nuvola main.cpp)
target_link_libraries(nuvola ${PCL_LIBRARIES})
Compilazione con QMake
TEMPLATE = app
CONFIG += console c++14
CONFIG -= app_bundle
CONFIG -= qt
CONFIG += link_pkgconfig
PKGCONFIG += eigen3
INCLUDEPATH += /usr/include/pcl-1.11
LIBS += -L/usr/lib/x86_64-linux-gnu -lpcl_common -lpcl_io -lpcl_features -lpcl_search
QT += widgets
SOURCES += \
main.cpp
Compilazione con Make
Per verificare quali sono gli switch di compilazione necessari per usare make si puo'usare
pkg-config --cflags --libs pcl_commons-1.7
anche in questo caso si deve ripetere l'operazione per ogni modulo utilizzato
Di seguito un semplice esempio di come leggere un file PCD, calcolare le normali e stampare i dati a schermo
===========================================
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/features/normal_3d.h>
using namespace std;
int main()
{
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
if (pcl::io::loadPCDFile<pcl::PointXYZ> ("/home/luca/gabriele.pcd", *cloud) == -1) //* load the file
{
PCL_ERROR ("Couldn't read file test_pcd.pcd \n");
return (-1);
}
//std::cout << "Loaded " << cloud->width * cloud->height << " data points from test_pcd.pcd with the following fields: " << std::endl;
/*for (size_t i = 0; i < cloud->points.size (); ++i)
std::cout << " " << cloud->points[i].x << " " << cloud->points[i].y << " " << cloud->points[i].z << std::endl;
*/
// Create the normal estimation class, and pass the input dataset to it
pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;
ne.setInputCloud (cloud);
// Create an empty kdtree representation, and pass it to the normal estimation object.
// Its content will be filled inside the object, based on the given input dataset (as no other search surface is given).
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ> ());
ne.setSearchMethod (tree);
// Output datasets
pcl::PointCloud<pcl::Normal>::Ptr cloud_normals (new pcl::PointCloud<pcl::Normal>);
// Use all neighbors in a sphere of radius 3cm
ne.setRadiusSearch (0.03);
// Compute the features
ne.compute (*cloud_normals);
//std::cout << endl << cloud_normals->size() << endl;
// cloud_normals->size () should have the same size as the input cloud->size ()*
int i = 0;
for (pcl::Normal n : *cloud_normals) {
//std::cerr << i << " n = " << n.normal_x << ", " << n.normal_y << ", " << n.normal_z << "\n";
std::cout << n.normal_x << "," << n.normal_y << "," << n.normal_z << "\n";
i++;
}
return 0;
}
Aggiornamento In realta' il Jtag USB funziona anche sui moduli cinesi Il problema risiede nell'ID USB della porta Jtag. Nel modulo...