/* Multigraph.c * by Rob Seib, 2014, August * Written for the Lego Multigraph, * this program gathers data from the user * and draws a corresponding artistic rendering. */ int keypressed = -1; //The value for user input const int LEFTKEY = 2; const int RIGHTKEY = 1; const int CENTREKEY = 3; int spirotype = 0; //The type of drawing. 0 = no spiro ; 1 = seamless ; 2 = bilateral ; 4 = four-sided long complexity = 1; //Default 1. Determines the period or how many times a given motor will turn one full rotation before the drawing returns to it's origin int myspeedA = 0; //The desired speed for motor A int myspeedB = 0; //Likewise for B int myspeedC = 0; //Etc string strMyspeedA; // string for holding myspeedA string strComplexity; //string for holding complexity value void waitkeypress() //Waits for a key press and assigns value to variable keypressed { keypressed = -1; //Reset keypress and wait to gain new value do{ keypressed = nNxtButtonPressed; }while(keypressed == -1); wait1Msec(500); } void drawthepattern() //Draws one full period allowing the pen to return to its point of origin { nMotorEncoder[motorB] = 0; while (nMotorEncoder[motorB] <= (complexity * 3 * 360 * 2)) //gear ratio is 3:1 and 360 is degrees for full circle and do twice { motor[motorA] = myspeedA; motor[motorB] = myspeedB; motor[motorC] = myspeedC; } motor[motorA] = 0; motor[motorB] = 0; motor[motorC] = 0; } task main() { //SYMMETRY / SPIROGRAPH SETTINGS eraseDisplay(); nxtDisplayStringAt(0,60,"LEGO MULTIGRAPH"); nxtDisplayStringAt(0,50,"Spin the paper?"); nxtDisplayStringAt(0,40,"(For spirograph-"); nxtDisplayStringAt(0,30,"like symmetry.)"); nxtDisplayStringAt(0,10,"Yes No"); waitkeypress(); if (keypressed == LEFTKEY)//If Symmetrical Yes is chosen { spirotype = 2; //Set to Bilateral symmetry, unless changed in the following eraseDisplay(); nxtDisplayStringAt(0,40,"Type of Symmetry?"); nxtDisplayStringAt(0,10,"Radial Bilateral"); waitkeypress(); if (keypressed == LEFTKEY) //If Radial is chosen { spirotype = 4; //Set to 4-sided symmetry, unless changed in the following eraseDisplay(); nxtDisplayStringAt(0,40,"Type of Radial?"); nxtDisplayStringAt(0,20,"Spirograph "); nxtDisplayStringAt(0,10," or 4-Sided"); waitkeypress(); if (keypressed == LEFTKEY) // If Seamless/Spirograph is chosen { spirotype = 1; //Set to Seamless/Spirograph Symmetry do { strMyspeedA = myspeedA; eraseDisplay(); nxtDisplayStringAt(0,60,"How closely-knit"); nxtDisplayStringAt(0,50,"between 1 and 20?"); nxtDisplayStringAt(0,40,"(1 is very close)"); nxtDisplayStringAt(45,25,strMyspeedA); nxtDisplayStringAt(0,10,"down OK up"); waitkeypress(); if (keypressed == RIGHTKEY) { myspeedA++; if (myspeedA > 20) myspeedA = 1; } else if (keypressed == LEFTKEY) { myspeedA--; if (myspeedA < 1) myspeedA = 20; } }while(keypressed != CENTREKEY); } } } //COMPLEXITY SETTINGS do { strComplexity = complexity; eraseDisplay(); nxtDisplayStringAt(0,60,"Please select"); nxtDisplayStringAt(0,50,"complexity value"); nxtDisplayStringAt(0,40,"between 0 and 60."); nxtDisplayStringAt(45,25,strComplexity); nxtDisplayStringAt(0,10,"down OK up"); waitkeypress(); if (keypressed == RIGHTKEY) { complexity++; if (complexity > 60) complexity = 0; } else if (keypressed == LEFTKEY) { complexity--; if (complexity < 0) complexity = 60; } }while(keypressed != CENTREKEY); if (complexity == 0) //Extremely basic setting { myspeedB = 25; myspeedC = 0; complexity = 1; //later on we will still have to have it turn one full circle therefore complexity is 1. the 0 was for user interface purposes to separate single motor from dual motor action. } else if (complexity == 1) //mildly basic { eraseDisplay(); nxtDisplayStringAt(0,40,"Type of Shape?"); nxtDisplayStringAt(0,10,"Ellipse Varied"); waitkeypress(); if (keypressed == LEFTKEY) //chose elliptical, arms go same direction { myspeedB = 25; myspeedC = -25; } else //chose triangular , arms go opposite directions { myspeedB = 25; myspeedC = 25; } } else if (complexity >= 2 && complexity <= 16) //Custom ratios. E.G. for a complexity of 2, we don't want to use speed of 2:1, because that's too slow (not optimal). The 'period' is still 2 at 40:20 { switch(complexity) { case 2: myspeedB = 40; myspeedC = 20; break; case 3: myspeedB = 30; myspeedC = 20; break; case 4: myspeedB = 28; myspeedC = 21; break; case 5: myspeedB = 25; myspeedC = 20; break; case 6: myspeedB = 24; myspeedC = 20; break; case 7: myspeedB = 28; myspeedC = 24; break; case 8: myspeedB = 32; myspeedC = 28; break; case 9: myspeedB = 27; myspeedC = 24; break; case 10: myspeedB = 30; myspeedC = 27; break; case 11: myspeedB = 22; myspeedC = 20; break; case 12: myspeedB = 24; myspeedC = 22; break; case 13: myspeedB = 26; myspeedC = 24; break; case 14: myspeedB = 28; myspeedC = 26; break; case 15: myspeedB = 30; myspeedC = 28; break; case 16: myspeedB = 32; myspeedC = 30; break; default: break; } } else //any complexity 17 or above is pretty straight forward { myspeedB = complexity; myspeedC = complexity - 1; } if (complexity >= 2) // Specify arms go same or opposite direction { eraseDisplay(); nxtDisplayStringAt(0,40,"Type of Shape?"); nxtDisplayStringAt(0,10,"Concave Convex"); waitkeypress(); if (keypressed == RIGHTKEY) myspeedC = myspeedC * (-1); } //GET PEN READY! eraseDisplay(); nxtDisplayStringAt(0,40,"Position a pen!"); nxtDisplayStringAt(45,10,"GO!"); keypressed = -1; do{ keypressed = nNxtButtonPressed; }while(keypressed != CENTREKEY); wait1Msec(500); //EXECUTE USER SELECTIONS switch (spirotype) { case 0: //Draw a non-spirograph drawthepattern(); break; case 1: //Draw a continuous spirograph while (1) { motor[motorA] = myspeedA; motor[motorB] = myspeedB; motor[motorC] = myspeedC; } break; case 2: //Draw a mirrored picture for (int i = 1; i <= 2; i++) { drawthepattern(); nMotorEncoder[motorA] = 0; while (nMotorEncoder[motorA] <= 7 * 180) //turn the paper 180 degrees (7:1 is the gear ratio) motor[motorA] = 25; motor[motorA] = 0; } break; case 4: //Draw a 4-point picture for (int i = 1; i <= 4; i++) { drawthepattern(); nMotorEncoder[motorA] = 0; while (nMotorEncoder[motorA] <= 7 * 90) //turn the paper 90 degrees (7:1 is the gear ratio) motor[motorA] = 25; motor[motorA] = 0; } break; default: break; } }