start hoverbrett visualization

This commit is contained in:
interfisch 2019-06-09 23:23:02 +02:00
parent 1c8c75ce57
commit 373dca44d6
5 changed files with 416 additions and 0 deletions

View File

@ -0,0 +1,102 @@
import processing.serial.*;
Serial serialport;
Visualization visVoltage;
Visualization visCurrent;
float voltage = 50;
float current = 0.0;
long lastReceive=0; //last time serial received
long lastDelay=0;
void setup() {
size(640, 360);
printArray(Serial.list());
serialport = new Serial(this, Serial.list()[2], 9600);
//vis = new BarV(150,150,10,100,0,100);
//vis = new BarH(150,150,100,10,0,100);
visVoltage = new Tacho(150,150,100,0,100);
//vis = new Direction(150,150,100,0,100,0,1);
visVoltage.setShowMinMax(true);
visVoltage.setTitle("Voltage [V]");
visCurrent= new Tacho(150+250,150,100,0,100);
visCurrent.setShowMinMax(true);
visCurrent.setTitle("Current [A]");
}
void draw() {
receive();
background(255);
visVoltage.setValue(voltage);
visCurrent.setValue(current);
visVoltage.drawVis();
visCurrent.drawVis();
fill(color(0,0,0));
textSize(12);
long _delay=lastDelay;
if (millis()-lastReceive>1000){ //show counting up if update too long ago
_delay=millis()-lastReceive;
}
text("Delay="+(_delay), 5,12);
}
public void receive()
{
byte[] inBuffer = new byte[8];
while(serialport.available()>0) {
//inBuffer = serialport.readBytes();
serialport.readBytes(inBuffer);
//if (inBuffer != null) {
voltage = extract_float(inBuffer,0);
current = extract_float(inBuffer,4);
//}
}
if (received){
lastDelay=millis()-lastReceive;
lastReceive=millis();
}
}
public int extract_uint16_t(byte array[], int startbyte) {
return ((int)array[startbyte] & 0xff) | ((int)array[startbyte+1] & 0xff)<<8;
}
public int extract_int16_t(byte array[], int startbyte) {
if ( ((int)array[startbyte+1] & 0x80) == 0x00 ) { //2's complement, not negative
return ( ((int)array[startbyte] & 0xff) | ((int)array[startbyte+1] & 0x7f)<<8 );
}else{ //value is negative
return -32768 + ( ((int)array[startbyte] & 0xff) | ((int)array[startbyte+1] & 0x7f)<<8 );
}
}
public float extract_float(byte array[], int startbyte) {
int MASK = 0xff;
int bits = 0;
int i = startbyte+3; //+3 because goes backwards and has 4 bytes
for (int shifter = 3; shifter >= 0; shifter--) {
bits |= ((int) array[i] & MASK) << (shifter * 8);
i--;
}
return Float.intBitsToFloat(bits);
}

View File

@ -0,0 +1,297 @@
abstract class Visualization
{
float value=0;
float value2=1;
PVector posOrigin = new PVector(100,100);
float valueMin=0;
float valueMax=100;
float value2Min=0; //value 2 for twodimensional visualization
float value2Max=1;
float valueMinRecord = Float.NaN; //nan means no value here
float valueMaxRecord = Float.NaN;
float value2MinRecord = Float.NaN; //nan means no value here
float value2MaxRecord = Float.NaN;
boolean showMinMax=false;
//default colors (not all used by every implementation)
color cmain = color(0,0,0);
color cscale = color(100,100,100);
color cborder = color(204,104,0);
color cmin = color(0,150,0);
color cmax = color(150,0,0);
color ctext = color(0,0,0);
int textsize=12;
float textWidthScale=1.0/2*this.textsize/2; //*text.length()*
int showdecimals=2;
String title="";
public abstract void drawVis();
public void setValue(float pv){
this.value=constrain(pv,valueMin,valueMax);
if (this.showMinMax){
if (Float.isNaN(this.valueMinRecord) || this.value<this.valueMinRecord){
this.valueMinRecord=this.value;
}
if (Float.isNaN(this.valueMaxRecord) || this.value>this.valueMaxRecord){
this.valueMaxRecord=this.value;
}
}
}
public void setValue2(float pv){
this.value2=constrain(pv,valueMin,valueMax);
if (this.showMinMax){
if (Float.isNaN(this.value2MinRecord) || this.value2<this.value2MinRecord){
this.value2MinRecord=this.value2;
}
if (Float.isNaN(this.value2MaxRecord) || this.value2>this.value2MaxRecord){
this.value2MaxRecord=this.value2;
}
}
}
public float getValueNormalized() {
return (this.value-this.valueMin)/(this.valueMax-this.valueMin);
}
public float getValueMinNormalized() {
return (this.valueMinRecord-this.valueMin)/(this.valueMax-this.valueMin);
}
public float getValueMaxNormalized() {
return (this.valueMaxRecord-this.valueMin)/(this.valueMax-this.valueMin);
}
public float getValue2Normalized() {
return (this.value2-this.value2Min)/(this.value2Max-this.value2Min);
}
public float getValue2MinNormalized() {
return (this.value2MinRecord-this.value2Min)/(this.value2Max-this.value2Min);
}
public float getValue2MaxNormalized() {
return (this.value2MaxRecord-this.value2Min)/(this.value2Max-this.value2Min);
}
public void setShowMinMax(boolean pshowMinMax){
this.showMinMax = pshowMinMax;
}
public void setcmain(color pc){
this.cmain=pc;
}
public void setcscale(color pc){
this.cscale=pc;
}
public void setcborder(color pc){
this.cborder=pc;
}
public void setcmin(color pc){
this.cmin=pc;
}
public void setcmax(color pc){
this.cmax=pc;
}
public void setctext(color pc){
this.ctext=pc;
}
public void setTitle(String pt) {
this.title=pt;
}
public void setshowdecimals(int pd) {
this.showdecimals=pd;
}
public String getFormattedValue(double pv){
if( ( (int)(pv*100)/100.0 )%1==0){
return ""+(int)pv;
}else{ //has decimals
return String.format("%."+this.showdecimals+"f", pv); //limit decimal places
}
}
}
public class BarV extends Visualization {
PVector size = new PVector(10,100);
public BarV(int px, int py, int pw, int ph, float pvmin, float pvmax) {
super.valueMin=pvmin;
super.valueMax=pvmax;
super.posOrigin= new PVector(px,py); //lower left corner
this.size = new PVector(pw,ph); //to the right and up
}
public void drawVis() {
rectMode(CORNERS);
textSize(super.textsize);
fill(super.cmain); noStroke();
rect(super.posOrigin.x,super.posOrigin.y,super.posOrigin.x+this.size.x,super.posOrigin.y-( this.size.y*super.getValueNormalized()) );
if (!Float.isNaN(super.valueMinRecord)){
stroke(super.cmin);
line(super.posOrigin.x,super.posOrigin.y-( this.size.y*super.getValueMinNormalized()) ,super.posOrigin.x+this.size.x,super.posOrigin.y-( this.size.y*super.getValueMinNormalized()) );
}
if (!Float.isNaN(super.valueMaxRecord)){
stroke(super.cmax);
line(super.posOrigin.x, super.posOrigin.y-( this.size.y*super.getValueMaxNormalized()), super.posOrigin.x+this.size.x,super.posOrigin.y-( this.size.y*super.getValueMaxNormalized()) );
}
noFill(); stroke(this.cborder);
rect(super.posOrigin.x,super.posOrigin.y,super.posOrigin.x+this.size.x,super.posOrigin.y- this.size.y );
//text
fill(super.ctext);
text(super.getFormattedValue(super.valueMin),super.posOrigin.x+this.size.x+1,super.posOrigin.y+super.textsize/2);
text(super.getFormattedValue(super.valueMax),super.posOrigin.x+this.size.x+1,super.posOrigin.y-this.size.y+super.textsize/2);
text(super.getFormattedValue(super.value),super.posOrigin.x+this.size.x+1,super.posOrigin.y-this.size.y/2+super.textsize/2);
//Title
text(super.title, super.posOrigin.x-super.title.length()*super.textWidthScale, super.posOrigin.y+super.textsize*1.5);
}
}
public class BarH extends Visualization {
PVector size = new PVector(10,100);
public BarH(int px, int py, int pw, int ph,float pvmin, float pvmax) {
super.valueMin=pvmin;
super.valueMax=pvmax;
super.posOrigin= new PVector(px,py); //lower left corner
this.size = new PVector(pw,ph); //to the right and up
}
public void drawVis() {
rectMode(CORNERS);
textSize(super.textsize);
fill(super.cmain); noStroke();
rect(super.posOrigin.x,super.posOrigin.y,super.posOrigin.x+( this.size.x*super.getValueNormalized()),super.posOrigin.y- this.size.y );
if (!Float.isNaN(super.valueMinRecord)){
stroke(super.cmin);
line(super.posOrigin.x+( this.size.x*super.getValueMinNormalized()),super.posOrigin.y,super.posOrigin.x+( this.size.x*super.getValueMinNormalized()),super.posOrigin.y- this.size.y );
}
if (!Float.isNaN(super.valueMaxRecord)){
stroke(super.cmax);
line(super.posOrigin.x+( this.size.x*super.getValueMaxNormalized()),super.posOrigin.y,super.posOrigin.x+( this.size.x*super.getValueMaxNormalized()),super.posOrigin.y- this.size.y );
}
noFill(); stroke(super.cborder);
rect(super.posOrigin.x,super.posOrigin.y,super.posOrigin.x+this.size.x,super.posOrigin.y- this.size.y );
//text
fill(super.ctext);
text(super.getFormattedValue(super.valueMin),super.posOrigin.x-super.getFormattedValue(super.valueMin).length()*super.textWidthScale,super.posOrigin.y-this.size.y-1);
text(super.getFormattedValue(super.valueMax),super.posOrigin.x+this.size.x-super.getFormattedValue(super.valueMax).length()*super.textWidthScale,super.posOrigin.y-this.size.y-1);
text(super.getFormattedValue(super.value),super.posOrigin.x+this.size.x/2-super.getFormattedValue(super.value).length()*super.textWidthScale,super.posOrigin.y-this.size.y-1);
//Title
text(super.title, super.posOrigin.x+this.size.x/2-super.title.length()*super.textWidthScale,super.posOrigin.y+this.size.y+1);
}
}
public class Tacho extends Visualization {
int size;
public Tacho(int px, int py, int psize, float pvmin, float pvmax) {
super.valueMin=pvmin;
super.valueMax=pvmax;
super.posOrigin= new PVector(px,py); //circle center
this.size = psize; //radius from the center
}
public void drawVis() {
rectMode(CORNERS);
textSize(super.textsize);
stroke(super.cmain);
float angle=PI-super.getValueNormalized()*PI; //0=right, positive=CCW
line(super.posOrigin.x,super.posOrigin.y,super.posOrigin.x+cos(angle)*this.size*0.8 ,super.posOrigin.y-sin(angle)*this.size*0.8); //draw tacho needle
if (!Float.isNaN(super.valueMinRecord)){
stroke(this.cmin);
float angleMin=PI-super.getValueMinNormalized()*PI; //0=right, positive=CCW
line(super.posOrigin.x+cos(angleMin)*this.size*0.65 ,super.posOrigin.y-sin(angleMin)*this.size*0.65,super.posOrigin.x+cos(angleMin)*this.size*0.75 ,super.posOrigin.y-sin(angleMin)*this.size*0.75); //draw tacho needle min
}
if (!Float.isNaN(super.valueMaxRecord)){
stroke(this.cmax);
float angleMax=PI-super.getValueMaxNormalized()*PI; //0=right, positive=CCW
line(super.posOrigin.x+cos(angleMax)*this.size*0.65 ,super.posOrigin.y-sin(angleMax)*this.size*0.65,super.posOrigin.x+cos(angleMax)*this.size*0.75 ,super.posOrigin.y-sin(angleMax)*this.size*0.75); //draw tacho needle max
}
stroke(this.cscale);
fill(super.ctext);
float _steps=0.1;
for (float i=0;i<=1+_steps; i+=_steps){
float a=PI-PI*i;
line(super.posOrigin.x+cos(a)*this.size*0.85 ,super.posOrigin.y-sin(a)*this.size*0.85 ,super.posOrigin.x+cos(a)*this.size ,super.posOrigin.y-sin(a)*this.size);
String _text=super.getFormattedValue(super.valueMin+(super.valueMax-super.valueMin)*i);
text(_text,super.posOrigin.x+cos(a)*this.size*1.1-_text.length()*super.textWidthScale-1 ,super.posOrigin.y-sin(a)*this.size*1.1+super.textsize/2-1);
}
//text
text(super.getFormattedValue(super.value),super.posOrigin.x-super.getFormattedValue(super.value).length()*super.textWidthScale,super.posOrigin.y+super.textsize/2-this.size*0.3);
//Title
text(super.title, super.posOrigin.x-super.title.length()*super.textWidthScale, super.posOrigin.y+super.textsize*1.5);
}
}
public class Direction extends Visualization {
int size;
public Direction(int px, int py, int psize,float pvmin, float pvmax, float pvlmin, float pvlmax) {
super.valueMin=pvmin;
super.valueMax=pvmax;
super.posOrigin= new PVector(px,py); //center
this.size = psize; //radius from the center
super.value2Min=pvlmin;
super.value2Max=pvlmax;
}
public void drawVis() {
rectMode(CORNERS);
textSize(super.textsize);
stroke(super.cborder); noFill();
ellipseMode(RADIUS); //centerx, centery, width,height for ellipse
ellipse(super.posOrigin.x, super.posOrigin.y, this.size,this.size);
stroke(super.cmain);
float angle=map(super.value,super.valueMin,super.valueMax,0,2*PI);
float _vecsize=this.size*( (super.value2-super.value2Min)/(super.value2Max-super.value2Min));
line(super.posOrigin.x,super.posOrigin.y,super.posOrigin.x+cos(angle)*_vecsize,super.posOrigin.y-sin(angle)*_vecsize);
line(super.posOrigin.x+cos(angle-0.1)*_vecsize*0.9,super.posOrigin.y-sin(angle-0.1)*_vecsize*0.9,super.posOrigin.x+cos(angle)*_vecsize,super.posOrigin.y-sin(angle)*_vecsize); //arrow
line(super.posOrigin.x+cos(angle+0.1)*_vecsize*0.9,super.posOrigin.y-sin(angle+0.1)*_vecsize*0.9,super.posOrigin.x+cos(angle)*_vecsize,super.posOrigin.y-sin(angle)*_vecsize);
//text
fill(super.ctext);
text("d="+super.getFormattedValue(super.value),super.posOrigin.x-super.getFormattedValue(super.value).length()*super.textWidthScale,super.posOrigin.y+super.textsize/2-this.size*0.3);
if (super.value2<super.value2Max){ //display only if in use
text("l="+super.getFormattedValue(super.value2),super.posOrigin.x-super.getFormattedValue(super.value2).length()*super.textWidthScale,super.posOrigin.y+super.textsize/2-this.size*0.3+super.textsize);
}
//Title
text(super.title, super.posOrigin.x-super.title.length()*super.textWidthScale, super.posOrigin.y+super.textsize*1.5);
}
}

View File

@ -0,0 +1,17 @@
float voltage=50.2;
float current=0;
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
Serial.begin(115200);
}
void loop() {
digitalWrite(LED_BUILTIN,!digitalRead(LED_BUILTIN));
voltage=constrain(voltage+random(-10,11)/100.0, 10*3.3,12*4.2);
current=constrain(current+random(-40,41)/10.0, 0,50);
Serial.write((uint8_t *) &voltage, sizeof(voltage));//float 4bytes
Serial.write((uint8_t *) &current, sizeof(voltage));//float 4bytes
delay(20);
}