mappare variabile in modo non lineare

Dovrei mappare una variabile in modo che abbia due tipi di linearità, uno prima e uno dopo un certo valore. Mi spiego meglio, ho un potenziometro ed un servo motore, il valore del primo modifica la posizione del secondo. Con il comando map() io gli dico di mappare il valore da 0 a 1023 in input e da 0 a 179 in output, quindi al movimento del potenziometro si muove il servo in maniera lineare, quando ad esempio il potenziometro è a metà il servo sarà a 90°...giusto? Ho fatto degli schemi per facilità, per ora siamo nel caso 1. Se io però volessi che il mio valore in input sia mappato in modo tale che a metà giro del potenziometro invece che a 90° il servo si posizioni a 45°, mantenendo però i punti di partenza e arrivo, quindi avendo un tipo di mappatura più ripido da 0° a 45° e più piano da 46° a 179°(caso 2)...è possibile da fare? Nel caso, sarebbe possibile dare alla variabile in uscita un andamento a curva per non avere un comportamento "spigoloso" (3)?

MATEMATICA!

la map è una funzione lineare, ovvero una retta, se disegni il grafico.

La formula è y=mx+q dove x è il valore di entrata, y il valore di uscita, m la "ripidità" della retta, e q è il valore che deve avere y quando x=0

Potresti usare una forma esponenziale: y= m x^2+q

Potresti usare la formula della parabola: y=ax^2+bx+c

oppure usare una funzionae logaritmica: y = m log(x)+q

etc...

disegna su un grafico i valori che vorresti ottenere

Grazie, in effetti mi ero dimenticato di dire una cosa che invece è importante...il valore in cui il servo deve essere ai 90° (o altro) non è fisso ma viene impostato dall'utente durante l'esecuzione del programma e quindi non posso fare conti preventivi. In pratica devo fare in modo che l'utilizzatore imposti il punto del potenziometro in cui vuole che il motore stia in quella posizione prefissata, e che prima e dopo i valori in uscita abbiano un andamento tale che comunque al servo arrivi sempre 0 quando è a inizio corsa e 179 quando è a fondo corsa...non so se mi sono spiegato, è un po' cervellotico! XD

Per Lesto: credo che tu abbia commesso un errore nella formula che chiami esponenziale. Verifica...

Comunque, Lesto ha ragione potresti usare l'equazione della parabola che passa per 3 punti o meglio 2 più l'origine.

E' meglio invertire gli assi per maggiore chiarezza: l'asse della ascisse X è la lettura del potenziometro (0-1023), mentre l'asse delle ordinate Y è la posizione del servo (0-180).

I primi due punti sono gli estremi (0;0) e (1023;180), mentre il terzo è variabile (X3;Y3), ad esempio (511;90).

è un *, comunque a parte la retta e la parabola che sono in forma canonica, le altre le ho sparate a caso :grin:

Lesto, l'esponenziale ha il numero di Nepero "e" come base dell'esponente X: y = m * e^x + q

hai ragione, la mia "esponensziale" in realtà era una sottospecie della parabola. Mea Culpa

Questo è con un punto intermedio lineare

long bilinearmap(long x, long in_min, long in_med, long in_max, long out_min, long out_med, long out_max)
{
  if (x < in_med)
	return (x - in_min) * (out_med - out_min) / (in_med - in_min) + out_min;
  else
	return (x - in_med) * (out_max - out_med) / (in_max - in_med) + out_med;
}

Esempio del secondo grafico

servo = bilinearmap(pot, 0, 511, 1023, 0, 45, 180);

Non ho controllato se compila e se funziona. Ma se ti fidi… :grin:

EDIT
Si può scrivere anche

long bilinearmap(long x, long in_min, long in_med, long in_max, long out_min, long out_med, long out_max)
{
  return (x<in_med)?((x-in_min)*(out_med-out_min)/(in_med-in_min)+out_min):((x-in_med)*(out_max-out_med)/(in_max-in_med)+out_med);
}

mi fido mi fido!! XD Devo fare un attimo mente locale per capirci qualcosa, anzi se tu fossi così gentile da spiegarmi qualcosa te ne sarei grato... :*

L'IF serve per discriminare se l'ordinata si trova prima o dopo il valore intermedio. Se si trova prima applico una mappatura che da in uscita un valore compreso tra il minimo e l'intermedio; mentre se è maggiore si avrà in uscita un valore compreso tra l'intermedio e il massimo. Come vedi ho duplicato la formula del map() originale (che trovi in WMath.h) modificando il minimo o il massimo in base alle necessità. La seconda versione è più compatta perché al posto dell'IF usa l'operatore ternario (che non è altro che un IF mascherato).

Grazie 1000! Appena ho tempo provo a vedere se riesco a fare qualcosa! XD