venerdì 8 marzo 2024

Realsense Docker

Aggiornamento:

Il container e' disponibile gia' compilato su Docker.com al mio account

https://hub.docker.com/repository/docker/c1p81/realsense_2004/general

 ============================================

Ho deciso di tirare fuori dal cassetto la D415 Realsense e come al solito montare l'SDK diventa sempre piu' difficile a causa delle politiche di Intel di dismissione dei propri dispositivi


 

Stavolta volevo provare la strada dell'ambiente docker ma ne' il container ufficiale ne' alcuni trovati su docker hub risultavano completamente funzionanti e me lo sono scritto da solo

(da modificare l'image_id)

Bash

docker run -it --rm  --privileged  -v /dev:/dev  -v "$HOME:/home/luca/"   --device-cgroup-rule "c 81:* rmw"     --device-cgroup-rule "c 189:* rmw"   b105279d1264 /bin/bash

Realsense Viewer

xhost +

docker run -d  --net=host --env="DISPLAY" --volume="$HOME/.Xauthority:/root/.Xauthority:rw"   -v /dev:/dev    --device-cgroup-rule "c 81:* rmw"     --device-cgroup-rule "c 189:* rmw"   2bd94ff6bc38 realsense-viewer

 

Save to disk

docker run -it --rm --privileged    -v /dev:/dev  -v "$HOME:/home/luca/"   --device-cgroup-rule "c 81:* rmw"     --device-cgroup-rule "c 189:* rmw"   34ea465a203e sh -c "cd /home/luca && rs-save-to-disk"

per creare il docker si usa il comando

docker build -t 20_04_real .

con il seguente Dockerfile


FROM public.ecr.aws/lts/ubuntu:20.04_stable

ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update \
&& apt-get install -qq -y --no-install-recommends \
build-essential \
cmake \
lsb-release \
git \
curl \
libssl-dev \
libusb-1.0-0-dev \
pkg-config \
libudev-dev \
libgtk-3-dev \
libglfw3-dev \
libgl1-mesa-dev \
libglu1-mesa-dev \
curl \
python3 \
python3-dev \
python3-pip \
libopencv-dev \
python3-opencv \
python3-numpy \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*


RUN mkdir -p /etc/apt/keyrings
RUN curl -sSf https://librealsense.intel.com/Debian/librealsense.pgp | tee /etc/apt/keyrings/librealsense.pgp > /dev/null


RUN echo "deb [signed-by=/etc/apt/keyrings/librealsense.pgp] https://librealsense.intel.com/Debian/apt-repo `lsb_release -cs` main" | tee /etc/apt/sources.list.d/librealsense.list
RUN apt-get update


RUN apt-get -y install librealsense2-dkms librealsense2-utils librealsense2-dev librealsense2-dbg librealsense2-udev-rules mc nano locales
RUN apt-get clean
RUN pip install pyrealsense2

RUN git clone https://github.com/IntelRealSense/librealsense
RUN cd librealsense
RUN mkdir /librealsense/build
WORKDIR /librealsense/build
RUN cmake ../ -DBUILD_EXAMPLES=true
RUN make

sabato 24 febbraio 2024

ODM

 Ho provato a vedere se ODM poteva essere idoneo per misurare l'altezza di un cumulo (o di una collinetta) usando fotogrammetria da terra con la camera del telefono cellulare

In un sito di prova e' stato verificato un errore inferiore a 30 cm su 5 m di altezza







Metashape vs ODM

Aggiornamento

Modificando il parametro da Volume Analysis a Model 3D, ODM ha un risultato comparabile con Metashape





Sto provando a fare fotogrammetria da terra tramite ODM e WEBODM  confrontando con Metashaoe

Per riferimento ho preso una piccola collina ad anfiteatro con 208 immagini riprese muovendosi attorno alla collina. ODM non riesce a capire che si tratta dello stesso oggetto e crea dei piani ognuno relativo al lato del perimetro su cui sono state fatte le foto, Metashape invece riesce a collegare i transetti ortogonali del lati dell'area e ricrea un unico oggetto geometricamente corretto

Un altro aspetto non trascurabile e' il tempo di calcolo: con parametri di default e con lo stesso numero di immagini Metashape su M1 ha impiegato meno di 15 minuti per terminare il calcolo, ODM su docker x86 ha impiegato oltre un'ora

Oggetto di riferimento

Se invece si fa un solo transetto come qui ODM risulta corretto anche dal punto di vista delle dimensioni stimate

Mesh creata con Metashape


Mesh creata con ODM


PointCloud da Metashape


PointCloud da ODM




martedì 13 febbraio 2024

AprilTags C++

Avevo gia' usato gli Apriltags per stimare le distanze 

Stavolta ho modificato il programma di esempio opencv_demo di Apriltag in modo da estrarre le matrici di rotazione e traslazione 


Per cercare di minimizzare il rumore di misura si sono fatto un dodecaedro con le fatte ricoperte di apriltag (le distanze relative dei tag sulle facce devono rimanere costanti ed dodecaedro permette sempre di esporre al minimo 2 ma quasi sempre 3 facce)



/* Copyright (C) 2013-2016, The Regents of The University of Michigan.
All rights reserved.

This software was developed in the APRIL Robotics Lab under the
direction of Edwin Olson, ebolson@umich.edu. This software may be
available under alternative licensing terms; contact the address above.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the Regents of The University of Michigan.
*/

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <ctype.h>
#include <math.h>
#include <errno.h>

#ifdef __linux__
#include <unistd.h>
#endif

#include "apriltag.h"
#include "tag36h11.h"
#include "tag25h9.h"
#include "tag16h5.h"
#include "tagCircle21h7.h"
#include "tagCircle49h12.h"
#include "tagCustom48h12.h"
#include "tagStandard41h12.h"
#include "tagStandard52h13.h"

#include "common/getopt.h"
#include "common/image_u8.h"
#include "common/pjpeg.h"
#include "common/zarray.h"
#include "apriltag_pose.h"

#define HAMM_HIST_MAX 10

int main(int argc, char *argv[])
{
getopt_t *getopt = getopt_create();

getopt_add_bool(getopt, 'h', "help", 0, "Show this help");
getopt_add_bool(getopt, 'd', "debug", 0, "Enable debugging output (slow)");
getopt_add_bool(getopt, 'q', "quiet", 0, "Reduce output");
getopt_add_string(getopt, 'f', "family", "tag36h11", "Tag family to use");
getopt_add_int(getopt, 'i', "iters", "1", "Repeat processing on input set this many times");
getopt_add_int(getopt, 't', "threads", "1", "Use this many CPU threads");
getopt_add_int(getopt, 'a', "hamming", "1", "Detect tags with up to this many bit errors.");
getopt_add_double(getopt, 'x', "decimate", "2.0", "Decimate input image by this factor");
getopt_add_double(getopt, 'b', "blur", "0.0", "Apply low-pass blur to input; negative sharpens");
getopt_add_bool(getopt, '0', "refine-edges", 1, "Spend more time trying to align edges of tags");

if (!getopt_parse(getopt, argc, argv, 1) || getopt_get_bool(getopt, "help")) {
printf("Usage: %s [options] <input files>\n", argv[0]);
getopt_do_usage(getopt);
exit(0);
}

const zarray_t *inputs = getopt_get_extra_args(getopt);

apriltag_family_t *tf = NULL;
const char *famname = getopt_get_string(getopt, "family");
if (!strcmp(famname, "tag36h11")) {
tf = tag36h11_create();
} else if (!strcmp(famname, "tag25h9")) {
tf = tag25h9_create();
} else if (!strcmp(famname, "tag16h5")) {
tf = tag16h5_create();
} else if (!strcmp(famname, "tagCircle21h7")) {
tf = tagCircle21h7_create();
} else if (!strcmp(famname, "tagCircle49h12")) {
tf = tagCircle49h12_create();
} else if (!strcmp(famname, "tagStandard41h12")) {
tf = tagStandard41h12_create();
} else if (!strcmp(famname, "tagStandard52h13")) {
tf = tagStandard52h13_create();
} else if (!strcmp(famname, "tagCustom48h12")) {
tf = tagCustom48h12_create();
} else {
printf("Unrecognized tag family name. Use e.g. \"tag36h11\".\n");
exit(-1);
}

apriltag_detector_t *td = apriltag_detector_create();
apriltag_detector_add_family_bits(td, tf, getopt_get_int(getopt, "hamming"));

switch(errno){
case EINVAL:
printf("\"hamming\" parameter is out-of-range.\n");
exit(-1);
case ENOMEM:
printf("Unable to add family to detector due to insufficient memory to allocate the tag-family decoder. Try reducing \"hamming\" from %d or choose an alternative tag family.\n", getopt_get_int(getopt, "hamming"));
exit(-1);
}

td->quad_decimate = getopt_get_double(getopt, "decimate");
td->quad_sigma = getopt_get_double(getopt, "blur");
td->nthreads = getopt_get_int(getopt, "threads");
td->debug = getopt_get_bool(getopt, "debug");
td->refine_edges = getopt_get_bool(getopt, "refine-edges");

int quiet = getopt_get_bool(getopt, "quiet");

int maxiters = getopt_get_int(getopt, "iters");

for (int iter = 0; iter < maxiters; iter++) {

int total_quads = 0;
int total_hamm_hist[HAMM_HIST_MAX];
memset(total_hamm_hist, 0, sizeof(int)*HAMM_HIST_MAX);
double total_time = 0;

if (maxiters > 1)
printf("iter %d / %d\n", iter + 1, maxiters);

for (int input = 0; input < zarray_size(inputs); input++) {

int hamm_hist[HAMM_HIST_MAX];
memset(hamm_hist, 0, sizeof(hamm_hist));

char *path;
zarray_get(inputs, input, &path);
if (!quiet)
printf("loading %s\n", path);
else
printf("%20s ", path);

image_u8_t *im = NULL;
if (str_ends_with(path, "pnm") || str_ends_with(path, "PNM") ||
str_ends_with(path, "pgm") || str_ends_with(path, "PGM"))
im = image_u8_create_from_pnm(path);
else if (str_ends_with(path, "jpg") || str_ends_with(path, "JPG")) {
int err = 0;
pjpeg_t *pjpeg = pjpeg_create_from_file(path, 0, &err);
if (pjpeg == NULL) {
printf("pjpeg failed to load: %s, error %d\n", path, err);
continue;
}

if (1) {
im = pjpeg_to_u8_baseline(pjpeg);
} else {
printf("illumination invariant\n");

image_u8x3_t *imc = pjpeg_to_u8x3_baseline(pjpeg);

im = image_u8_create(imc->width, imc->height);

for (int y = 0; y < imc->height; y++) {
for (int x = 0; x < imc->width; x++) {
double r = imc->buf[y*imc->stride + 3*x + 0] / 255.0;
double g = imc->buf[y*imc->stride + 3*x + 1] / 255.0;
double b = imc->buf[y*imc->stride + 3*x + 2] / 255.0;

double alpha = 0.42;
double v = 0.5 + log(g) - alpha*log(b) - (1-alpha)*log(r);
int iv = v * 255;
if (iv < 0)
iv = 0;
if (iv > 255)
iv = 255;

im->buf[y*im->stride + x] = iv;
}
}
image_u8x3_destroy(imc);
if (td->debug)
image_u8_write_pnm(im, "debug_invariant.pnm");
}

pjpeg_destroy(pjpeg);
}

if (im == NULL) {
printf("couldn't load %s\n", path);
continue;
}

printf("image: %s %dx%d\n", path, im->width, im->height);

zarray_t *detections = apriltag_detector_detect(td, im);

if (errno == EAGAIN) {
printf("Unable to create the %d threads requested.\n",td->nthreads);
exit(-1);
}

for (int i = 0; i < zarray_size(detections); i++) {
apriltag_detection_t *det;
zarray_get(detections, i, &det);
// ********************************************************
/*apriltag_detection_info_t info;
info.det = det;
info.tagsize = 5; //dimensione del tag
info.fx = 10; // lunghezza focale camera in pixels asse x
info.fy = 10; // lunghezza focale camera in pixels asse y
info.cx = 10; // centro focale camera in pixels asse x
info.cy = 10; // centro focale camera in pixels asse x
*/
//apriltag_pose_t pose;
//double err = estimate_tag_pose(&info, &pose);
//double x = pose.R->data[0];
//double y = pose.R->data[1];
//double z = pose.R->data[2];
//double translation_on_axes_1 = pose.t->data[0];
//double translation_on_axes_2 = pose.t->data[1];
//double translation_on_axes_3 = pose.t->data[3];

// ********************************************************
if (!quiet)
printf("detection %3d: id (%2dx%2d)-%-4d, hamming %d, margin %8.3f\n",
i, det->family->nbits, det->family->h, det->id, det->hamming, det->decision_margin);

hamm_hist[det->hamming]++;
total_hamm_hist[det->hamming]++;
}

apriltag_detections_destroy(detections);

if (!quiet) {
timeprofile_display(td->tp);
}

total_quads += td->nquads;

if (!quiet)
printf("hamm ");

for (int i = 0; i < HAMM_HIST_MAX; i++)
printf("%5d ", hamm_hist[i]);

double t = timeprofile_total_utime(td->tp) / 1.0E3;
total_time += t;
printf("%12.3f ", t);
printf("%5d", td->nquads);

printf("\n");

image_u8_destroy(im);
}


printf("Summary\n");

printf("hamm ");

for (int i = 0; i < HAMM_HIST_MAX; i++)
printf("%5d ", total_hamm_hist[i]);
printf("%12.3f ", total_time);
printf("%5d", total_quads);
printf("\n");

}

// don't deallocate contents of inputs; those are the argv
apriltag_detector_destroy(td);

if (!strcmp(famname, "tag36h11")) {
tag36h11_destroy(tf);
} else if (!strcmp(famname, "tag25h9")) {
tag25h9_destroy(tf);
} else if (!strcmp(famname, "tag16h5")) {
tag16h5_destroy(tf);
} else if (!strcmp(famname, "tagCircle21h7")) {
tagCircle21h7_destroy(tf);
} else if (!strcmp(famname, "tagCircle49h12")) {
tagCircle49h12_destroy(tf);
} else if (!strcmp(famname, "tagStandard41h12")) {
tagStandard41h12_destroy(tf);
} else if (!strcmp(famname, "tagStandard52h13")) {
tagStandard52h13_destroy(tf);
} else if (!strcmp(famname, "tagCustom48h12")) {
tagCustom48h12_destroy(tf);
}

getopt_destroy(getopt);

return 0;
}



lunedì 12 febbraio 2024

martedì 6 febbraio 2024

RF1100-232 USB

 Il piano originale era...usare CC1101 come su Flipper Zero con un dispositivo già pronto ma a basso costo..

La scelta e' caduta su qesto



In linea di principio doveva diventare il clone di Yard Stick One (a meno di 1/10 del prezzo) magari appoggiandosi su RFQuack o cc1101-tools

L'esecuzione e' stata pessima...ma andiamo con ordine

La scheda mi e' arrivata da Aliexpress senza uno straccio di istruzioni d'uso ed anche la pagina del venditore non mi era di aiuto. Collegando il dispositivo vedevo un convertitore seriale-TTL CP2012 ma inviando dati sulla /dev/ttyUSB0 nessuna risposta e tanto meno segni dal led integrato

Aprendo il case si vedono i chip CP2012, un ATMega48PA ed il CC1101 quindi dalla USB si invia comandi all'ATMega che li reinvia al CC1101 tramite SPI....tranne per il fatto  che il microcontrollore non ha un booloader Arduino (c'e' da dire che ci sono le piazzole per saldare i connettori di MISO/MOSI e SCLK quindi non tutto e' perduto per la programmabilita')








ho trovato questo vecchio link che spiega come inviare le impostazioni di trasmissione  

http://www.yesyes.info/index.php/electronics/rf1100-232-rf-433mhz-transceiver-module/

in pratica sembra che questi dispositivi non siano nati per sniffare traffico ma solo per comunicare in modo seriale..in pratica si puo' impostare il canale, la potenza e poco piu' ... niente modulazione per esempio

Frugando su GitHub ho trovato questo link

https://github.com/acontini/CC1101_USB

Avvertenza...nel rar c'e' un eseguibile windows che virustotale segnala come virus...io sono su Linux ..ci sono alcuni documenti tra cui un eseguibile in C che sembra il firmware del ATMega48PA

Nel pacchetto c'e' anche un PDF di documentazione con la mail dell'assistenza tecnica...ho provato a contattarla ma la mail e' tornata indietro...adesso il dominio sembra appartenere ad una ditta che produce occhiali (maledizione)

La scheda viene inizializzata in 9600, canale 0, massima potenza ed ID 1. Dopo di cio' c'e' un loop infinito in  cui i bytes del buffer di trasmissione vengono mandati al CC1101 con un carattere di SYNC alla fine

#include <reg52.h>
#include <intrins.h>
#define INT8U unsigned char
#define INT16U unsigned int
sfr WDT_CONTR =0Xe1; //watchdog
sbit KEY1 =P3^6; //Key1 uguale al bit 6 porta 3
sbit KEY2 =P3^7;
sbit led =P2^5;
sbit led3=P2^0;
sbit led2=P2^1;
sbit led1=P2^2;
sbit led0=P2^3;
INT8U TxBuf[4];
INT8U send_f;
//when i=100. delay=1.5ms
static void delay(unsigned int s)
{
unsigned int i;
for(i=0; i<s; i++);
}
void UART_init()
{
SCON = 0x50; /* uart in mode 1 (8 bit), REN=1 */
TMOD = TMOD | 0x20 ; /* Timer 1 in mode 2 */
TH1 = 0xFD; /* 9600 Bds at 11.059MHz */
TL1 = 0xFD; /* 9600 Bds at 11.059MHz */
//IE =0x90;
TR1 = 1; /* Timer 1 run */
ET1 =0;
ES=1;
PS=1;
EA =1;
}
void Sendchar(unsigned char c)
{
SBUF=c;
while(TI==0);
TI=0;
}
void print_string(unsigned char* p)
{
while(*p !='\0')
{
Sendchar(*p++);
}
}
//--------------------------------------------------------------------------------------------------
// com_interrup()
//--------------------------------------------------------------------------------------------------
com_interrupt(void) interrupt 4 using 3
{
if(RI) {
RI=0;
TxBuf[2]=SBUF;
send_f=1;
send_f=1;
led=1;
}
}
void main(void)
{
INT8U leng =0;
INT8U i,k=0;
INT8U RxBuf[4]={0};
INT8U rxcount;
INT8U TxBuf[30];
led=1;
rxcount=0xff;
TxBuf[2]=2;
TxBuf[3]=0;
UART_init();
P0=0x00;
led1=0;
for(i=0; i<30; i++)
{
TxBuf[i]=i;
}
Sendchar(0xA3); //Comandi set serial port baud rate
Sendchar(0x3A);
Sendchar(0x02); //Imposta la baudrate a 9600 (1:4800,2:9600, 3:19200)
delay(6000);
Sendchar(0xA7); //Set Channel
Sendchar(0x7A);
Sendchar(0x00); //Setta canale 0 (da 00 a 255)
delay(6000);
Sendchar(0xAB); //Set TX Power
Sendchar(0xBA);
Sendchar(0x0A); //0A :10DBM (valori permessi 00,05,07,0A)
delay(6000);
Sendchar(0xA9); //Set Module ID
Sendchar(0x9A);
Sendchar(0x00); //
Sendchar(0x01); //Due bytes : da 0 a 65535
delay(6000);
delay(6000);
// WDT_CONTR=0x3c;
while(1) //loop
{
WDT_CONTR=0x3c;
if(KEY1==0)
{
delay(10);
while(!KEY1)
{
delay(10);
}
led1=0;
print_string("abcdefghijklmnopqrstuvwxyzABCD");
led1=1;
delay(750);
for(i=0;i<23;i++)
{
Sendchar(TxBuf[i]);
}
delay(750); .
Sendchar(0x66); //carattere di SYNC
}
delay(450);
led1=1;
delay(100);
}
}

Per la configurazione vera e propria della radio ci sono indicazioni in
ma non sono riuscito a trovare il modo di far passare i comandi dalla USB verso il CC1101

per esempio nella libreria si trova per cambiare il numero di canale si usa la funzione
setChannel che scrive nel registro 0x0A il valore del canale scelto
i parametri per la configurazione visti qui sono invece 0xA7
#define CC1101_CHANNR       0x0A        // Channel number

void ELECHOUSE_CC1101::setChannel(byte ch){
chan = ch;
SpiWriteReg(CC1101_CHANNR,   chan);
}

 void ELECHOUSE_CC1101::SpiWriteReg(byte addr, byte value)
{
  SpiStart();
  digitalWrite(SS_PIN, LOW);
  while(digitalRead(MISO_PIN));
  SPI.transfer(addr);
  SPI.transfer(value);
  digitalWrite(SS_PIN, HIGH);
  SpiEnd();
}

Debugger integrato ESP32S3

Aggiornamento In realta' il Jtag USB funziona anche sui moduli cinesi Il problema risiede  nell'ID USB della porta Jtag. Nel modulo...