Týden 10: Propojení s počítačem, programování aplikace

Tematem tohoto týdne stalo propojení s počítačem a programování aplikace, která umožní uživatelí vizualně analizovat data z senzorů atd. K tomu to učelu ja jsem použil volnou grafickou knihovnu a IDE Processing. Je velmi podobná aplikaci Arduino IDE, která je často použivána při programovaní mikrokontroleru, což velmi usnadňuje praci. I když nastroj je dost jednoduchý, graphické zpracovavaní výžaduje nejakou praci a matematické znalostí, což se úkaže v kodu dvou aplikaci niž. Jako senzor byl vyúžit joystick. Arduino byla zaprogramována na přenos dat přes seriový port a jejich transformaci do vhodných parametrů.

Jednoduché malování

První aplikace realizuje jednoduchou malovačku, která je řizená pomoci joystiku. Při její navrhu jsem řešil takové problemy jako převod souřadnic do vhodných pro počitač a taky jejich skalovaní. Joystick je zapojen na analogové piny Arduino Nano, a proto data jsou ve formatu [0:1023] pro souřadnice X a Y. Při posunu nuly jsem se setkal s neidealností senzoru, což se projevilo nekorektnými souřadnicemi: [503, 509] místo [512,512]. Ještě musíme si pamatovát, že joystick mapuje souřadnice na čtverec, což vede k různé rychlosi v uhlech a krajních bodech pracovní zony joystiku. Obsahuje taky pasmo necitlivosti.

        
            import processing.serial.*;

            Serial myPort;
            float x, y;
            int key;
            final int max_x = 800;
            final int max_y = 800;
            float dumping = 50.0;

            int last_drawer[] = {max_x/2, max_y/2};
            int drawer[] = {max_x/2, max_y/2};

            void setup() {
            println(Serial.list());
            String portName = Serial.list()[0];
            myPort = new Serial(this, portName, 9600);
            myPort.bufferUntil('\n');
            size(800, 800);
            background(255);
            stroke(0);
            strokeWeight(2);
            }

            void draw() {
            fill(0);
            line(drawer[0], drawer[1], last_drawer[0], last_drawer[1]);
            fill(255);
            last_drawer[0] = drawer[0];
            last_drawer[1] = drawer[1];
            if(key==0)
            {
                background(255);
            }
            }


            void serialEvent(Serial myPort) {
            String inString = myPort.readStringUntil('\n');
            if (inString != null) {
                inString = trim(inString);
                parseData(inString);
            }
            }

            float[] change_coord(float x, float y){
            float r = sqrt(x*x + y*y);
            if (r>2.0){ r=2.0; }
            float phi = atan2(y, x);
            float x_new = r*cos(phi);
            float y_new = r*sin(phi);
            float[] new_coord = {x_new, y_new};
            return new_coord;
            }

            void parseData(String data) {
            String[] pairs = splitTokens(data, ";");
            
            for (int i = 0; i < pairs.length; i++) {
                String[] keyValue = splitTokens(pairs[i], "=");
                if (keyValue.length == 2) {
                if (keyValue[0].equals("X")) {
                    x = int(keyValue[1])/dumping;
                } else if (keyValue[0].equals("Y")) {
                    y = int(keyValue[1])/dumping;
                } else if (keyValue[0].equals("button")) {
                    key = int(keyValue[1]);
                }
                }
                
                
                float[] new_coord = change_coord(x,y);
                
                if (drawer[0] + x > max_x){
                drawer[0] = max_x;
                }
                else if (drawer[0] + x < 0){
                drawer[0] = 0;
                }
                else{
                drawer[0] += new_coord[0];
                }
                
                if (drawer[1] + y > max_y){
                drawer[1] = max_x;
                }
                else if (drawer[1] + y < 0){
                drawer[1] = 0;
                }
                else{
                drawer[1] += new_coord[1];
                }
                print("x=");
                print(new_coord[0]);
                print(" , y=");
                print(new_coord[1]);
                print(", key=");
                println(key);
            }
            }
        
    

Kreslení grafů

Další aplikace realizuje vizualní zobrazovaní X a Y souřadnic z senzoru ve formě grafů a polohovaní bodu na ploše. Zasadnými momenty jsou spiše nejaké speciality Processing, který je realizovan na Java, kterou bohužel neumím. Taky důležitou poznamkou bude asi to, že musíte aspoň nejak umět programovat asynchronní aplikace, což se mi trochu povedlo, ale jen trochu. Současné zpracovavaní dat ze seriového portu, jejich transformace a zobrazení přinutí vás k zamýšlení nad sdilením paměti a podobným věcem.

        
            import processing.serial.*;

            Serial myPort;  
            ArrayList points = new ArrayList();
            ArrayList xTime = new ArrayList(); 
            ArrayList yTime = new ArrayList();  
            long startTime;
            boolean parsing = false;
            boolean drawing = false;
            long last_frame = 0;
            int time_frame = 580;

            int max_x = 600;
            int max_y = 600;

            int last_drawer[] = {max_x/2, max_y/2};
            int drawer[] = {max_x/2, max_y/2};

            void setup() {
            size(1200, 600);
            println(Serial.list());
            String portName = Serial.list()[0];
            myPort = new Serial(this, portName, 9600);
            myPort.bufferUntil('\n');
            startTime = millis();
            stroke(0);
            }

            void draw() {
            background(255);
            rect(0, 0, 600, 600);
            rect(600, 0, 600, 300);
            rect(600, 300, 600, 300);
            //println("parsing " + parsing);
            if (!parsing){
                //println("parsing " + parsing);
                drawing = true;
                drawXYPlane();
                drawTimeGraph(xTime, 600, 0);
                drawTimeGraph(yTime, 600, 300);
                drawing = false;
            }
            }

            void serialEvent(Serial myPort) {
            //println("drawing " + drawing);
            if (!drawing){
                parsing = true;
                String inString = myPort.readStringUntil('\n');
                if (inString != null) {
                inString = trim(inString);
                parseData(inString);
                }
                parsing = false;
            }
            
            }

            void parseData(String data) {
            String[] pairs = split(data, ';');
            float x = 0, y = 0;
            int button = 0;  // Добавляем переменную для button

            for (String pair : pairs) {
                String[] keyValue = split(pair, '=');
                if (keyValue.length == 2) {
                String key = keyValue[0].trim();
                String value = keyValue[1].trim();

                if (key.equals("X")) {
                    x = float(value);
                    if (abs(x) < 1){ x=0; }
                } else if (key.equals("Y")) {
                    y = float(value);
                    if (abs(y) < 1){ y=0; }
                } else if (key.equals("button")) {
                    button = int(value);
                }
                }
            }
            
            if (drawer[0] + x > max_x){
                drawer[0] = max_x;
                }
                else if (drawer[0] + x < 0){
                drawer[0] = 0;
                }
                else{
                drawer[0] += x/10;
                }
                
                if (drawer[1] + y > max_y){
                drawer[1] = max_x;
                }
                else if (drawer[1] + y < 0){
                drawer[1] = 0;
                }
                else{
                drawer[1] += y/10;
                }

            points.add(new PVector(x, y));
            xTime.add(new PVector((millis() - last_frame) / time_frame, x));
            yTime.add(new PVector((millis() - last_frame) / time_frame, y));
            
            if (xTime.size() >= time_frame) {
                last_frame = millis();
                xTime.remove(0);
                yTime.remove(0);
            }
            
            }

            void drawXYPlane() {
            strokeWeight(4);
            fill(0);
            line(drawer[0], drawer[1], last_drawer[0], last_drawer[1]);
            fill(255);
            last_drawer[0] = drawer[0];
            last_drawer[1] = drawer[1];
            strokeWeight(1);
            }

            void drawTimeGraph(ArrayList data, int xOffset, int yOffset) {
            pushMatrix();
            translate(xOffset, yOffset);
            stroke(0);
            noFill();
            beginShape();
            for (int i = 0; i < data.size(); i++) {
                PVector p = data.get(i);
                float y_new = map(p.y, -100, 100, 0, 300);
                vertex(i, y_new);
            }
            endShape();
            popMatrix();
            }