TCM Simulator
Arial & Jenny
Instructor: Rudi
CONCEPTION AND DESIGN:
My partner and I are into traditional Chinese culture and we have been exposed to traditional Chinese medicine(TCM) since little. Moreover, according to the ideology people have right now which is science, TCM is ignored under the context. In order to introduce it to a wider range of people and based on our own experience, we decided to make a project to convey the basic knowledge of TCM. The whole interaction process is to prescribe a patient according to his symptoms. We have three pages in total, the starting page, the symptom page, the prescription page. Considering the limited knowledge of the participants, we designed two modes, one is easy mode and the other is hard mode. The easy one would provide you with the direct herbs you need and the weight you should weigh respectively. The hard one would only provide you with the prompt symptoms and the total weight you need, which means you should explore the traits of the herbs by yourself to decide which to use. Once you pull out the drawer, the traits of the herbs will pop up. In this case, we intended to use digitalRead to detect the current in the wire, if the value is 1 then the traits will pop up, otherwise don’t. After picking out the herbs you need(we have one or more bags within a drawer showcasing different weight of the herbs), you weigh it by the steelyard(we have weight inside, 5g, 10g, 30g…) and put them into the furnace one by one to let the RFID detect the genre.
However, during the user testing, the whole system was not that smooth. There was poor connection between the naked wire and the conductive tape, so the traits unexpectedly appear and disappear which leads to our next fabrication revision. Also, as the whole process is complicated, most of the participants were not able to figure out what they should do which means we need a simpler version and a clearer instruction. Whatsmore, most of the participants didn’t know how to use the steelyard which made the interaction much more difficult.
So basically, we need to change the way the computer detects the state of the drawers and provide a more simple instruction. We used reed switches afterwards to make the value more stable. We made a clearer oral instruction. However, when we were presenting our project, the process seemed to be too long and eliminated the interactivity that we expected. It seemed a little bit tedious and unpolished.
In this case, we made another version for the IMA show. Reserving the function of the drawers, we changed the whole interaction form. When participants pull out the drawer, one at each time, the pictures of the traits we composed at first and the educational video we found will pop up at the same time. The video will stay at the center, the picture will stay at the up-left corner. The result turned out to be successful and effective, letting a lot of people know our design and the message we wanted to convey.
FABRICATION AND PRODUCTION:
Fabrication part
The process of making the cabinet is essential. We first laser cut out the 20 drawers and adjusted the grid to it which took me a lot of effort(19 versions of the grid…). I poked 4 holes behind each drawer on the outside box so that I could fit the wires in stably(as you can see in the second picture that there is a contrast).
However, during the user testing, the connection was unstable(probably because of the grid and the backplate of the outside box was not stuck together), so we stuck everywhere we could between the outside box and the grid, and used a reed switch for each. One thing we didn’t notice was that when we stuck everything together, the flexibility of the grid was eliminated, and two of the drawers could not fit in. We used hammers to break some of the glued intersections and the grid became loose and those two drawers went back to their places.
After all the laser cutting was done, we sprayed the cabinet. Due to the damage we caused, we went to facility service to make up for our mistake… After spraying, we used gold ink to color the characters and the bags.
My partner did the 3D printing part and some of the feedback from the user said it was too modern to be matched with the cabinet. By using sander, I sanded out a pot so it would appear more natural and ancient.
Digital production
Because of the poor connection, as the wires could not be evenly plain enough to touch the tape at the same time, professor Rudi suggested we turned to reed switch. It successfully fixed our problem! This is the most important issue in our project, if it could not work perfectly, it will affect participants’ experience.
Another problem is the value that Arduino read is not stable, sometimes it couldn’t detect the change of the current, sometimes it would went wrong when sending values to Processing. Professor Andy helped me with this part, he opened the example code and run the digitalRead inside, afterwards he turned back to the original code and it run smoothly. I didn’t really get it but it’s a great way to fix the problem though.
I used photoshop to edit pictures of the traits.
My partner explored the RFID part, it could not work as truly detecting the right or wrong prescription so we fake it till make it. Also, as we didn’t know there are more than 20 pins on Mega, we seperated the RFID part with the herb chosing part onto two computers which was kind of split. As it made the process too long and was lack of visualization, for better message delivery and experience, we deleted the part and made the IMA show version.
We originally designed the position of the pop up pictures to be random and participants could drag them to anywhere they want, but the outcome was not that easy, the picture would hardly move. Due to the limited time, we didn’t fix the problem and abandoned it in the last version.
CONCLUSIONS:
The message we intended to convey by this project is to popularize TCM and trigger the interests of the mass. I don’t know whether I have reached the goal or not, but from the reactions of those participants during IMA show, I felt greatly encouraged and more confident in my project.
Well, let’s first talk about the setbacks. The visualization was unpolished because we spent too much time finding the materials for the IMA show version, we barely have time to iterate it. The videos were super lagged, we don’t know whether it’s because of their length or the problem of Processing itself. Whatsmore, as the participants could pick the herbs up and smell them, the smells of the herbs themselves were ruined by the plywood. Those are where should improve.
However, there are three groups of participants that impressed me most and they provided me with great insights again and again into my project.
A mother brought her kid to tryout my project, it was obvious that the kid has already been exposed to TCM and his mother encouraged him to try to pull out all the medicine inside. While he was smelling the herbs and watching the introductions, he even talked to his mother that which herbs are good for her and grandma. Also, he was the only one who went over all the drawers. Even though I didn’t introduce much on my project, I felt resonant with the family and was glad that the mother could have such mindset.
A pair of international friend came to discuss about our perception towards TCM and one of them proposed that ‘A thing shouldn’t be regarded as invaluable because of not being scientific, maybe it’s just because people could not understand it!’ What striked me most was when he tapped my shoulder after interact with my project and said ‘I am with you’. That was the moment when I felt the cognitions joint together.
The last one was my last participator, she was the only one who understood my make-up medicine ‘snow’, ‘spring’ and ‘dew’. A Dream of Red Mensions is a classical masterpiece, within the plot, also aligned with TCM idea, a kind of pill is needed to be taken with the first snow in September. She asked me about it and our ideas were the same. This was when I felt finally there is someone who could understand my subtle detail! A lot of people were wondering why these three waters could be regarded as medicine and could be stored in the wooden box, I just explained to them that we designed it as a bridge for easier comprehension. My idea was ‘snow’ is cold in nature, it could calm patients’ inner fire; ‘sping’ is always fluent, it could help patients with their overwhelming maridians; ‘dew’ is fresh, so it could clean up the intestines. These are based on the saying of one of the famous TCM doctors, ‘TCM is using the power from the nature to balance human body and the surroundings.’ It’s good to know there is someone who could read my mind, haha.
The project is just a beginning of the journey, there are way more to explore and develop.
After all, from my personal perspctive, a great project needs to contain profound or thoughful insights in it which could arouse different vioces. Interactivity is just the first step. Only with the notion and idea could we move further in design.
DISASSEMBLY:
APPENDIX
Easy mode
Hard mode
IMA show version
Code
Arduino
Cabinet(each pin is connected to a drawer)
int box1 = 21; int box2 = 2; int box3 = 3; int box4 = 4; int box5 = 5; int box6 = 6; int box7 = 7; int box8 = 8; int box9 = 9; int box10 = 10; int box11 = 11; int box12 = 12; int box13 = 13; int box14 = 14; int box15 = 15; int box16 = 16; int box17 = 17; int box18 = 18; int box19 = 19; int box20 = 20; void setup() { Serial.begin(9600); // pu.t your setup code here, to run once: pinMode(box1, INPUT_PULLUP); pinMode(box2, INPUT_PULLUP); pinMode(box3, INPUT_PULLUP); pinMode(box4, INPUT_PULLUP); pinMode(box5, INPUT_PULLUP); pinMode(box6, INPUT_PULLUP); pinMode(box7, INPUT_PULLUP); pinMode(box8, INPUT_PULLUP); pinMode(box9, INPUT_PULLUP); pinMode(box10, INPUT_PULLUP); pinMode(box11, INPUT_PULLUP); pinMode(box12, INPUT_PULLUP); pinMode(box13, INPUT_PULLUP); pinMode(box14, INPUT_PULLUP); pinMode(box15, INPUT_PULLUP); pinMode(box16, INPUT_PULLUP); pinMode(box17, INPUT_PULLUP); pinMode(box18, INPUT_PULLUP); pinMode(box19, INPUT_PULLUP); pinMode(box20, INPUT_PULLUP); } void loop() { // put your main code here, to run repeatedly: int state1 = digitalRead(box1); int state2 = digitalRead(box2); int state3 = digitalRead(box3); int state4 = digitalRead(box4); int state5 = digitalRead(box5); int state6 = digitalRead(box6); int state7 = digitalRead(box7); int state8 = digitalRead(box8); int state9 = digitalRead(box9); int state10 = digitalRead(box10); int state11 = digitalRead(box11); int state12 = digitalRead(box12); int state13 = digitalRead(box13); int state14 = digitalRead(box14); int state15 = digitalRead(box15); int state16 = digitalRead(box16); int state17 = digitalRead(box17); int state18 = digitalRead(box18); int state19 = digitalRead(box19); int state20 = digitalRead(box20); Serial.print(state1); Serial.print(","); Serial.print(state2); Serial.print(","); Serial.print(state3); Serial.print(","); Serial.print(state4); Serial.print(","); Serial.print(state5); Serial.print(","); Serial.print(state6); Serial.print(","); Serial.print(state7); Serial.print(","); Serial.print(state8); Serial.print(","); Serial.print(state9); Serial.print(","); Serial.print(state10); Serial.print(","); Serial.print(state11); Serial.print(","); Serial.print(state12); Serial.print(","); Serial.print(state13); Serial.print(","); Serial.print(state14); Serial.print(","); Serial.print(state15); Serial.print(","); Serial.print(state16); Serial.print(","); Serial.print(state17); Serial.print(","); Serial.print(state18); Serial.print(","); Serial.print(state19); Serial.print(","); Serial.print(state20); Serial.println(); delay(10); }
RFID
**-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --*Example sketch / program showing how to read data from a PICC to serial. * -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --*This is a MFRC522 library example; for further details and other examples see: https://github.com/miguelbalboa/rfid * * Example sketch/program showing how to read data from a PICC (that is: a RFID Tag or Card) using a MFRC522 based RFID * Reader on the Arduino SPI interface. * * When the Arduino and the MFRC522 module are connected (see the pin layout below), load this sketch into Arduino IDE * then verify/compile and upload it. To see the output: use Tools, Serial Monitor of the IDE (hit Ctrl+Shft+M). When * you present a PICC (that is: a RFID Tag or Card) at reading distance of the MFRC522 Reader/PCD, the serial output * will show the ID/UID, type and any data blocks it can read. Note: you may see "Timeout in communication" messages * when removing the PICC from reading distance too early. * * If your reader supports it, this sketch/program will read all the PICCs presented (that is: multiple tag reading). * So if you stack two or more PICCs on top of each other and present them to the reader, it will first output all * details of the first and then the next PICC. Note that this may take some time as all data blocks are dumped, so * keep the PICCs at reading distance until complete. * * @license Released into the public domain. * * Typical pin layout used: * ----------------------------------------------------------------------------------------- * MFRC522 Arduino Arduino Arduino Arduino Arduino * Reader/PCD Uno/101 Mega Nano v3 Leonardo/Micro Pro Micro * Signal Pin Pin Pin Pin Pin Pin * ----------------------------------------------------------------------------------------- * RST/Reset RST 9 5 D9 RESET/ICSP-5 RST * SPI SS SDA(SS) 10 53 D10 10 10 * SPI MOSI MOSI 11 / ICSP-4 51 D11 ICSP-4 16 * SPI MISO MISO 12 / ICSP-1 50 D12 ICSP-1 14 * SPI SCK SCK 13 / ICSP-3 52 D13 ICSP-3 15 * * More pin layouts for other boards can be found here: https://github.com/miguelbalboa/rfid#pin-layout */ #include #include #define RST_PIN 5 // Configurable, see typical pin layout above #define SS_PIN 10 // Configurable, see typical pin layout above MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance void setup() { Serial.begin(9600); // Initialize serial communications with the PC while (!Serial) ; // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4) SPI.begin(); // Init SPI bus mfrc522.PCD_Init(); // Init MFRC522 delay(4); // Optional delay. Some board do need more time after init to be ready, see Readme mfrc522.PCD_DumpVersionToSerial(); // Show details of PCD - MFRC522 Card Reader details Serial.println(F("Scan PICC to see UID, SAK, type, and data blocks...")); } void loop() { // Reset the loop if no new card present on the sensor/reader. This saves the entire process when idle. if (!mfrc522.PICC_IsNewCardPresent()) { return; } // Select one of the cards if (!mfrc522.PICC_ReadCardSerial()) { return; } // Dump debug info about the card; PICC_HaltA() is automatically called mfrc522.PICC_DumpToSerial(&(mfrc522.uid)); }
Processing
RFID
import processing.serial.*; import processing.sound.*; SoundFile file1; SoundFile file2; //PFont myFont; Serial myPort; String val; boolean card1Detected = false; boolean card2Detected = false; boolean card3Detected = false; boolean card4Detected = false; boolean card5Detected = false; boolean card6Detected = false; boolean card7Detected = false; boolean card8Detected = false; boolean card9Detected = false; boolean card10Detected = false; boolean card11Detected = false; boolean card12Detected = false; boolean card13Detected = false; boolean card14Detected = false; boolean card15Detected = false; boolean card16Detected = false; boolean card17Detected = false; boolean card18Detected = false; boolean card19Detected = false; boolean card20Detected = false; boolean card21Detected = false; boolean card22Detected = false; boolean card23Detected = false; boolean card24Detected = false; boolean card25Detected = false; boolean card26Detected = false; boolean card27Detected = false; boolean card28Detected = false; boolean card29Detected = false; boolean card30Detected = false; //boolean card30Detected = false; //boolean card31Detected = false; long lastDetectionTime = 0; // 记录最后一次检测到卡的时间 int timeout = 10000; // 设置超时时间为20秒 boolean timeoutActive = false; // 超时计时器是否激活 int isDetectedValue1 = 0; int isDetectedValue2 = 0; int isDetectedValue3 = 0; int isDetectedValue4 = 0; int isDetectedValue5 = 0; PImage image1, image2; // 图像对象 void setup() { //size(640, 360); fullScreen(); println("Available serial ports: " + Serial.list()); myPort = new Serial(this, Serial.list()[5], 9600); myPort.bufferUntil('\n'); background(0); file1 = new SoundFile(this, "success-1-6297.mp3"); file2 = new SoundFile(this, "wah-wah-sad-trombone-6347.mp3"); // 加载图像,确保图像文件在项目的根目录下或者指定了正确的路径 image1 = loadImage("success.jpg"); image2 = loadImage("fail.jpg"); if (image1 == null) { println("Error loading image1"); } else { println("Image1 loaded successfully"); } if (image2 == null) { println("Error loading image2"); } else { println("Image2 loaded successfully"); } //resetDetection(); } void draw(){ if (card1Detected) { stroke(10); fill(255); textSize(50); text("Peony Root 30g ", 50, 100 ); println("card1Detected"); } if (card2Detected) { stroke(10); fill(255); textSize(50); text("Licorice 20g ", 500, 100); println("card2Detected"); } if (card3Detected) { stroke(10); fill(255); textSize(50); text("Firewood 30g ", 950, 100 ); println("card3Detected"); } if (card4Detected) { stroke(10); fill(255); textSize(50); text("Angelica 30g ", 1400, 100); println("card4Detected"); } if (card5Detected) { stroke(10); fill(255); textSize(50); text("Wolfiporia 30g ", 50, 250 ); println("card1Detected"); } if (card6Detected) { stroke(10); fill(255); textSize(50); text("Atractylodes 30g ", 500, 250); println("card2Detected"); } if (card7Detected) { stroke(10); fill(255); textSize(50); text("Spring 100g ", 950, 250 ); println("card3Detected"); } if (card8Detected) { stroke(10); fill(255); textSize(50); text("Milk Vetch root 30g ", 1300, 250); println("card4Detected"); } if (card9Detected) { stroke(10); fill(255); textSize(50); text("Licorice 10g ", 50, 400 ); println("card1Detected"); } if (card10Detected) { stroke(10); fill(255); textSize(50); text("Firewood 5g ", 500, 400); println("card2Detected"); } if (card11Detected) { stroke(10); fill(255); textSize(50); text("Angelica 5g ", 950, 400 ); println("card3Detected"); } if (card12Detected) { stroke(10); fill(255); textSize(50); text("Atractylodes 10g ", 1300, 400); println("card4Detected"); } if (card13Detected) { stroke(10); fill(255); textSize(50); text("Dried Orange Peel 5g ", 50, 400 ); println("card1Detected"); } if (card14Detected) { stroke(10); fill(255); textSize(50); text("Jute 5g ", 500, 400); println("card2Detected"); } if (card15Detected) { stroke(10); fill(255); textSize(50); text("Ginseng 5g ", 950, 400 ); println("card3Detected"); } if (card16Detected) { stroke(10); fill(255); textSize(50); text("Snow 100g ", 1300, 400); println("card4Detected"); } if (card17Detected) { stroke(10); fill(255); textSize(50); text("Milk Vetch Root 50g ", 50, 550 ); println("card1Detected"); } if (card18Detected) { stroke(10); fill(255); textSize(50); text("Atractylodes 50g ", 500, 550); println("card2Detected"); } if (card19Detected) { stroke(10); fill(255); textSize(50); text("Wind-Proof Grass 30g ", 950, 550 ); println("card3Detected"); } if (card20Detected) { stroke(10); fill(255); textSize(50); text("Jujube 5g ", 1300, 550); println("card4Detected"); } if (card21Detected) { stroke(10); fill(255); textSize(50); text("Cinnamon 10g ", 50, 700 ); println("card1Detected"); } if (card22Detected) { stroke(10); fill(255); textSize(50); text("Ginger 10g ", 500, 700); println("card2Detected"); } if (card23Detected) { stroke(10); fill(255); textSize(50); text("Peony Root 10g ", 950, 700 ); println("card3Detected"); } if (card24Detected) { stroke(10); fill(255); textSize(50); text("Licorice 5g ", 1300, 700); println("card4Detected"); } if (card25Detected) { stroke(10); fill(255); textSize(50); text("Dew 100g ", 50, 850 ); println("card1Detected"); } if (card26Detected) { stroke(10); fill(255); textSize(50); text("Mid-Summer 10g ", 500, 850); println("card2Detected"); } if (card27Detected) { stroke(10); fill(255); textSize(50); text("Bitterness 5g ", 950, 850 ); println("card3Detected"); } if (card28Detected) { stroke(10); fill(255); textSize(50); text("Ginseng 10g ", 1300, 850); println("card4Detected"); } if (card29Detected) { stroke(10); fill(255); textSize(50); text("Scrutellaria 10g ", 50, 1000 ); println("card1Detected"); } checkCardsAndDisplay(); } void serialEvent(Serial myPort) { val = myPort.readStringUntil('\n'); if (val != null) { val = trim(val); println("Received UID: " + val); if (!timeoutActive && (card1Detected || card2Detected)) { lastDetectionTime = millis(); // 在检测到第一张卡后开始计时 timeoutActive = true; // 激活超时计时器 } if (val.equals("0 0D D3 1E DE 1E 08 04 00 03 D4 57 FA 7B CE 73 90 [ 0 0 0 ]")) { card1Detected = true; println("Card 1 detected"); isDetectedValue1 = 1; } else if (val.equals("0 1D D3 1E DE 0E 08 04 00 03 94 55 01 EB 4D 46 90 [ 0 0 0 ]")) { card2Detected = true; println("Card 2 detected"); isDetectedValue1 = 2; } else if (val.equals("0 2D D3 1E DE 3E 08 04 00 03 12 B5 84 9C AB 4B 90 [ 0 0 0 ]")) { card3Detected = true; println("Card 3 detected"); isDetectedValue1 = 3; } else if (val.equals("0 3D D3 1E DE 2E 08 04 00 03 CC D4 33 12 5A 9E 90 [ 0 0 0 ]")) { card4Detected = true; println("Card 4 detected"); isDetectedValue1 = 4; } else if (val.equals("0 4D D3 1E DE 5E 08 04 00 03 85 46 73 50 65 E8 90 [ 0 0 0 ]")) { card5Detected = true; println("Card 5 detected"); isDetectedValue1 = 5; } else if (val.equals("0 5D D3 1E DE 4E 08 04 00 03 0F C2 A6 88 18 14 90 [ 0 0 0 ]")) { card6Detected = true; println("Card 6 detected"); isDetectedValue1 = 6; } else if (val.equals("0 6D D3 1E DE 7E 08 04 00 03 74 0F F8 7E A5 CB 90 [ 0 0 0 ]")) { card7Detected = true; println("Card 7 detected"); isDetectedValue1 = 7; } //else { // println("Received unknown card UID"); //} //} else { // println("No data received or incomplete data"); } if (val.equals("0 7D D3 1E DE 6E 08 04 00 03 A5 8E F4 33 2E DE 90 [ 0 0 0 ]")) { card8Detected = true; println("Card 8 detected"); isDetectedValue2 = 1; } else if (val.equals("0 8D D3 1E DE 9E 08 04 00 03 15 9E BA 3C 20 6C 90 [ 0 0 0 ]")) { card9Detected = true; println("Card 9 detected"); isDetectedValue2 = 2; } else if (val.equals("0 9D D3 1E DE 8E 08 04 00 03 CA 79 7C E9 BB 3B 90 [ 0 0 0 ]")) { card10Detected = true; println("Card 10 detected"); isDetectedValue2 = 3; } else if (val.equals("0 AD D3 1E DE BE 08 04 00 03 A0 6E 95 17 DA C1 90 [ 0 0 0 ]")) { card11Detected = true; println("Card 11 detected"); isDetectedValue2 = 4; } else if (val.equals("0 BD D3 1E DE AE 08 04 00 03 1D E7 6D 86 71 4C 90 [ 0 0 0 ]")) { card12Detected = true; println("Card 12 detected"); isDetectedValue2 = 5; } else if (val.equals("0 CD D3 1E DE DE 08 04 00 03 22 93 D0 EA FF AF 90 [ 0 0 0 ]")) { card13Detected = true; println("Card 13 detected"); isDetectedValue2 = 6; } else if (val.equals("0 DD D3 1E DE CE 08 04 00 03 02 AA F4 48 4A 4C 90 [ 0 0 0 ]")) { card14Detected = true; println("Card 14 detected"); isDetectedValue2 = 7; } else if (val.equals("0 ED D3 1E DE FE 08 04 00 03 25 07 05 F0 45 86 90 [ 0 0 0 ]")) { card15Detected = true; println("Card 15 detected"); isDetectedValue2 = 8; } else if (val.equals("0 FD D3 1E DE EE 08 04 00 03 4C BB B8 5C 0D 7A 90 [ 0 0 0 ]")) { card16Detected = true; println("Card 16 detected"); isDetectedValue2 = 9; } else { // println("Received unknown card UID"); } //else { // println("No data received or incomplete data"); //} if (val.equals("0 0D D4 1E DE 19 08 04 00 03 3A 5D 4A 0F 28 1E 90 [ 0 0 0 ]")) { card17Detected = true; println("Card 17 detected"); isDetectedValue3 = 1; } else if (val.equals("0 1D D4 1E DE 09 08 04 00 03 CF 75 A4 E9 22 96 90 [ 0 0 0 ]")) { card18Detected = true; println("Card 18 detected"); isDetectedValue3 = 2; } else if (val.equals("0 2D D4 1E DE 39 08 04 00 03 73 E1 09 02 EE 63 90 [ 0 0 0 ]")) { card19Detected = true; println("Card 19 detected"); isDetectedValue3 = 3; } else if (val.equals("0 6D D3 1E DE 7E 08 04 00 03 74 0F F8 7E A5 CB 90 [ 0 0 0 ]")) { card7Detected = true; println("Card 7 detected"); isDetectedValue3 = 4; } else { // println("Received unknown card UID"); } if (val.equals("0 3D D4 1E DE 29 08 04 00 03 77 78 BC B0 0A 3C 90 [ 0 0 0 ]")) { card20Detected = true; println("Card 20 detected"); isDetectedValue4 = 1; } else if (val.equals("0 4D D4 1E DE 59 08 04 00 03 E2 4E 7C D3 A6 5B 90 [ 0 0 0 ]")) { card21Detected = true; println("Card 21 detected"); isDetectedValue4 = 2; } else if (val.equals("0 6D CA 1E DE 67 08 04 00 03 A8 B2 9F D9 FE 27 90 [ 0 0 0 ]")) { card22Detected = true; println("Card 22 detected"); isDetectedValue4 = 3; } else if (val.equals("0 8D CA 1E DE 87 08 04 00 03 E4 08 1B 42 C4 3D 90 [ 0 0 0 ]")) { card23Detected = true; println("Card 23 detected"); isDetectedValue4 = 4; } else if (val.equals("0 9D CA 1E DE 97 08 04 00 03 94 17 AA D4 BF F7 90 [ 0 0 0 ]")) { card24Detected = true; println("Card 24 detected"); isDetectedValue4 = 5; } else if (val.equals("0 AD CA 1E DE A7 08 04 00 03 2A 22 CB E7 82 0D 90 [ 0 0 0 ]")) { card25Detected = true; println("Card 25 detected"); isDetectedValue4 = 6; } else { // println("Received unknown card UID"); } if (val.equals("0 3D D4 1E DE 29 08 04 00 03 77 78 BC B0 0A 3C 90 [ 0 0 0 ]")) { card20Detected = true; println("Card 20 detected"); isDetectedValue5 = 1; } else if (val.equals("0 6D CA 1E DE 67 08 04 00 03 A8 B2 9F D9 FE 27 90 [ 0 0 0 ]")) { card22Detected = true; println("Card 22 detected"); isDetectedValue5 = 2; } else if (val.equals("0 BD CA 1E DE B7 08 04 00 03 DD 6E C4 09 C8 D9 90 [ 0 0 0 ]")) { card26Detected = true; println("Card 26 detected"); isDetectedValue5 = 3; } else if (val.equals("0 8D D3 1E DE 9E 08 04 00 03 15 9E BA 3C 20 6C 90 [ 0 0 0 ]")) { card9Detected = true; println("Card 9 detected"); isDetectedValue5 = 4; } else if (val.equals("0 CD CA 1E DE C7 08 04 00 03 77 AE 93 10 C6 AB 90 [ 0 0 0 ]")) { card27Detected = true; println("Card 27 detected"); isDetectedValue5 = 5; } else if (val.equals("0 DD CA 1E DE D7 08 04 00 03 68 87 32 94 6A 7A 90 [ 0 0 0 ]")) { card28Detected = true; println("Card 28 detected"); isDetectedValue5 = 6; } else if (val.equals("0 AD CA 1E DE A7 08 04 00 03 2A 22 CB E7 82 0D 90 [ 0 0 0 ]")) { card25Detected = true; println("Card 25 detected"); isDetectedValue5 = 7; } else if (val.equals("0 ED CA 1E DE E7 08 04 00 03 98 92 4A 7F EB 99 90 [ 0 0 0 ]")) { card29Detected = true; println("Card 29 detected"); isDetectedValue5 = 8; } } void checkCardsAndDisplay() { if (card1Detected && card2Detected && card3Detected && card4Detected && card5Detected && card6Detected && card7Detected) { //println("Both cards detected, displaying image1"); image(image1, 0, 0, width, height); if (file1.isPlaying() == false) { file1.play(); } resetDetection(); //} else if (card1Detected ^ card2Detected) { // //println("Only one card detected, displaying image2"); // image(image2, 0, 0, width, height); // resetDetection(); } else if (card30Detected) { image(image2, 0, 0, width, height); if (file2.isPlaying() == false) { file2.play(); } //file2.rate(2); } if (card8Detected && card9Detected && card10Detected && card11Detected && card12Detected && card13Detected && card14Detected && card15Detected && card16Detected) { //println("Both cards detected, displaying image1"); image(image1, 0, 0, width, height); if (file1.isPlaying() == false) { file1.play(); } resetDetection(); //} else if (card1Detected ^ card2Detected) { // //println("Only one card detected, displaying image2"); // image(image2, 0, 0, width, height); // resetDetection(); } else if (card30Detected) { image(image2, 0, 0, width, height); if (file2.isPlaying() == false) { file2.play(); } } if (card17Detected && card18Detected && card19Detected && card7Detected ) { //println("Both cards detected, displaying image1"); image(image1, 0, 0, width, height); if (file1.isPlaying() == false) { file1.play(); } resetDetection(); //} else if (card1Detected ^ card2Detected) { // //println("Only one card detected, displaying image2"); // image(image2, 0, 0, width, height); // resetDetection(); } else if (card30Detected) { image(image2, 0, 0, width, height); } if (card20Detected && card21Detected && card22Detected && card23Detected && card24Detected && card25Detected) { //println("Both cards detected, displaying image1"); image(image1, 0, 0, width, height); if (file1.isPlaying() == false) { file1.play(); } resetDetection(); //} else if (card1Detected ^ card2Detected) { // //println("Only one card detected, displaying image2"); // image(image2, 0, 0, width, height); // resetDetection(); } else if (card30Detected) { image(image2, 0, 0, width, height); if (file2.isPlaying() == false) { file2.play(); } } if (card20Detected && card22Detected && card26Detected && card9Detected && card27Detected && card28Detected && card25Detected && card29Detected) { //println("Both cards detected, displaying image1"); image(image1, 0, 0, width, height); if (file1.isPlaying() == false) { file1.play(); } resetDetection(); //} else if (card1Detected ^ card2Detected) { // //println("Only one card detected, displaying image2"); // image(image2, 0, 0, width, height); // resetDetection(); } else if (card30Detected) { image(image2, 0, 0, width, height); if (file2.isPlaying() == false) { file2.play(); } } } void resetDetection() { timeoutActive = false; } void keyPressed() { card30Detected = true; }
Presentation version
import processing.serial.*; Serial serialPort; int NUM_OF_VALUES_FROM_ARDUINO = 20; /* CHANGE THIS ACCORDING TO YOUR PROJECT */ //int NUM_OF_xBOX = 6; //int NUM_OF_yBOX = 6; int NUM_OF_IMG = 20; int NUM_OF_PATIENT = 5; int NUM_OF_DOC = 5; int NUM_OF_PRE = 5; int NUM_OF_PROMPT=5; //int NUM_OF_BUTTON = 1; int numImages = 20; // 图像数量 float spacing = 150; // 图像间距 float imageWidth = 1181/2; // 图像宽度 float imageHeight = 944/2; // 图像高度 float scroll = 0; // 鼠标滚动的偏移量 PFont myFont; int m_pre; /* This array stores values from Arduino */ int arduino_values[] = new int[NUM_OF_VALUES_FROM_ARDUINO]; //int arduino_values1[] = new int[NUM_OF_BUTTON]; PImage[] images = new PImage[NUM_OF_IMG]; PImage angelica1; PImage angelica2; //PImage[] images_angelica = new PImage[NUM_OF_ANGELICA]; PImage atractylodes1; PImage atractylodes2; PImage atractylodes3; //PImage[] images_atractylodes = new PImage[NUM_OF_ATRACTYLODES]; PImage bitterness; PImage cinnamon; PImage dew; PImage dried_orange_peel; PImage firewood1; PImage firewood2; //PImage[] images_firewood = new PImage[NUM_OF_FIREWOOD]; PImage ginger; PImage ginseng1; PImage ginseng2; //PImage[] images_ginseng = new PImage[NUM_OF_GINSENG]; PImage jujube; PImage jute; PImage licorice1; PImage licorice2; PImage licorice3; PImage licorice4; //PImage[] images_licorice = new PImage[NUM_OF_LICORICE]; PImage midsummer; PImage milkvetch1; PImage milkvetch2; //PImage[] images_milkvetch = new PImage[NUM_OF_MILKVETCH]; PImage peony1; PImage peony2; //PImage[] images_peony = new PImage[NUM_OF_PEONY]; PImage scutellaria; PImage snow; PImage spring; PImage wolf; PImage wpg; PImage[] images_patient = new PImage[NUM_OF_PATIENT]; PImage img21; PImage img22; PImage img23; PImage img24; PImage img25; PImage[] images_doc = new PImage[NUM_OF_DOC]; PImage img26; PImage img27; PImage img28; PImage img29; PImage img30; PImage[] images_pre = new PImage[NUM_OF_PRE]; PImage img31; PImage img32; PImage img33; PImage img34; PImage img35; PImage patient; PImage easymode_guizhi; PImage prompt; PImage start; PImage sym; PImage[] images_prompt = new PImage[NUM_OF_PROMPT]; PImage promptXY; PImage promptBZYQ; PImage promptGZ; PImage promptYPFS; PImage promptXX; int mode = 0; float imgX[]= new float[NUM_OF_IMG]; float imgY[] = new float[NUM_OF_IMG]; void setup() { //size(700, 700); fullScreen(); rectMode(CENTER); textAlign(CENTER, CENTER); printArray(Serial.list()); serialPort = new Serial(this, "COM5", 9600); imageMode(CENTER); for (int i=0; i < 20; i++) { imgX[i] = random(1754/4.8,width-1754/2.4); imgY[i] = random(1240/4.8, height-1240/2.4); } //load images of the herbs angelica1 = loadImage("Angelica_BZYQ.png"); angelica2 = loadImage("Angelica_xiaoyao.png"); atractylodes1 = loadImage("Atrac_BZYQ.png"); atractylodes2 = loadImage("Atrac_xiaoyao.png"); atractylodes3 = loadImage("Atrac_YPFS.png"); bitterness = loadImage("bitter.png"); cinnamon = loadImage("cinnamon.png"); dew = loadImage("dew.png"); dried_orange_peel = loadImage("DOP.png"); firewood1 = loadImage("FW_BZYQ.png"); firewood2 = loadImage("FW_xiaoyao.png"); ginger = loadImage("Ginger.png"); ginseng1 = loadImage("Ginseng_BZYQ.png"); ginseng2 = loadImage("Ginseng_xiexin.png"); jujube = loadImage("jujube.png"); jute = loadImage("Jute.png"); licorice1 = loadImage("Licorice_BZYQ.png"); licorice2 = loadImage("Licorice_guizhi.png"); licorice3 = loadImage("Licorice_xiaoyao.png"); licorice4 = loadImage("Licorice_xiexin.png"); midsummer = loadImage("Mid_sum.png"); milkvetch1 = loadImage("MVR_BZYQ.png"); milkvetch2 = loadImage("MVR_YPFS.png"); peony1 = loadImage("PR_guizhi.png"); peony2 = loadImage("PR_xiaoyao.png"); scutellaria = loadImage("Scute.png"); snow = loadImage("snow.png"); spring = loadImage("spring.png"); wolf = loadImage("Wolf.png"); wpg = loadImage("WPG.png"); img21 = loadImage("patient_1.png"); img22 = loadImage("doc_1.png"); img23 = loadImage("patient_2.png"); img24 = loadImage("doc_2.png"); img25 = loadImage("patient_3.png"); img26 = loadImage("doc_3.png"); img27 = loadImage("patient_4.png"); img28 = loadImage("doc_4.png"); img29 = loadImage("patient_5.png"); img30 = loadImage("doc_5.png"); img31 = loadImage("Xiao_Y_S.png"); img32 = loadImage("BZYQ_T.png"); img33 = loadImage("Cinna_T.png"); img34 = loadImage("YPFS.png"); img35 = loadImage("Mid_Sum_T.png"); patient = loadImage("patient.png"); easymode_guizhi = loadImage("easymode_guizhi.png"); prompt = loadImage("prompt.png"); start = loadImage("start_back.jpg"); sym = loadImage("sym.jpg"); promptXY = loadImage("xiaoyao_prompt.png"); promptBZYQ= loadImage("BZYQ_prompt.png");; promptGZ= loadImage("guizhi_prompt.png");; promptYPFS= loadImage("YPFS_prompt.png");; promptXX= loadImage("xiexin_prompt.png");; images[0]= angelica1; images[1]= atractylodes1; images[2]= bitterness; images[3] = cinnamon; images[4]= dew; images[5]= dried_orange_peel; images[6]= firewood1; images[7]= ginger; images[8]= ginseng1; images[9]= jujube; images[10]= jute; images[11]= licorice1; images[12]= midsummer; images[13]= milkvetch1; images[14]= peony1; images[15]= scutellaria; images[16]= snow; images[17]= spring; images[18]= wolf; images[19]= wpg; images_patient[0] = img21; images_patient[1] = img23; images_patient[2] = img25; images_patient[3] = img27; images_patient[4] = img29; images_doc[0] = img22; images_doc[1] = img24; images_doc[2] = img26; images_doc[3] = img28; images_doc[4] = img30; images_pre[0] = img31; images_pre[1] = img32; images_pre[2] = img33; images_pre[3] = img34; images_pre[4] = img35; images_prompt[0]=promptXY; images_prompt[1]=promptBZYQ; images_prompt[2]=promptGZ; images_prompt[3]=promptYPFS; images_prompt[4]=promptXX; m_pre= int(random(0, 5)); } void draw() { background(start); getSerialData(); //start page if (mode == 0) { drawButton(0.5*width, 0.5*height, 0.2*width, 0.15*height, 1, "START!!!"); } if (mode == 1) { drawDescription(); } else if (mode == 2) { drawSymptom(); } else if (mode == 3) { drawEasymode(); } else if (mode == 4) { drawHardmode(); } else if(mode==5){ drawSuccess(); } } void drawDescription() { myFont = createFont("隶书", 60); textFont(myFont); String textDisplay = "You are a CTM(Chinese Traditional Medicine) doctor \n who is working to prescribe medicine to your patients. \n Based on their symptoms and the corresponding remedy, \n please pick the right herbs for the prescription.\n 你是一个中医药大夫,\n需要根据病人的症状或者所给出的药方配出一副药"; text(textDisplay, 0.5*width, 0.5*height); drawButton(0.5*width, 0.7*height, 0.2*width, 0.1*height, 2, "Continue"); //if(arduino_values[21] < 100) { //mode = 5; //} } void drawSymptom() { image(patient, 0.5*width, 0.5*height, 620, 570); //pictures of patients and docs image(images_patient[m_pre], 0.2*width, 0.35*height, 1181/1.2, 944/1.2); image(images_doc[m_pre], 0.8*width, 0.5*height, 1181/1.2, 944/1.2); //buttons easy and hard drawButton(0.4*width, 0.85*height, 0.15*width, 0.1*height, 3, "EASY"); drawButton(0.6*width, 0.85*height, 0.15*width, 0.1*height, 4, "HARD"); } void drawEasymode() { image(images_pre[m_pre], 0.8*width, 0.5*height, 1417/2, 2125/2); for (int i = 0; i<20; i++) { if (arduino_values[i] ==1 ) { if (m_pre == 0) { images[0] = angelica2; images[1] =atractylodes2; images[6] =firewood2; images[11] =licorice3; images[14] =peony2; } else if (m_pre == 3) { images[1]= atractylodes3; images[13]=milkvetch2; } else if (m_pre == 4) { images[8]= ginseng2; images[11]= licorice4; } else if (m_pre==2) { images[11]= licorice2; } image(images[i], imgX[i], imgY[i], 1754/2.4, 1240/2.4 ); if (mouseX>imgX[i]-0.05*width && mouseX<imgX[i]+0.05*width && mouseY<imgY[i]+0.05*height&& mouseY>imgY[i]-0.05*height) { if (mousePressed) { imgX[i] = mouseX; imgY[i] = mouseY; } } } } textSize(40); text("You can drag the pictures anywhere you want!", width/2, 24*height/25); } void drawHardmode() { image(images_prompt[m_pre], 0.8*width, 0.5*height, 1417/1.5, 2125/1.5); for (int i = 0; i<20; i++) { if (arduino_values[i] ==1) { if (m_pre == 0) { images[0] = angelica2; images[1] =atractylodes2; images[6] =firewood2; images[11] =licorice3; images[14] =peony2; } else if (m_pre == 3) { images[1]= atractylodes3; images[13]=milkvetch2; } else if (m_pre == 4) { images[8]= ginseng2; images[11]= licorice4; } else if (m_pre==2) { images[11]= licorice2; } image(images[i], imgX[i], imgY[i], 1754/2.4, 1240/2.4 ); if (mouseX>imgX[i]-0.05*width && mouseX<imgX[i]+0.05*width && mouseY<imgY[i]+0.05*height&& mouseY>imgY[i]-0.05*height) { if (mousePressed) { imgX[i] = mouseX; imgY[i] = mouseY; } } } } textSize(40); text("You can drag the pictures anywhere you want!", width/2, 24*height/25); } void getSerialData() { while (serialPort.available() > 0) { String in = serialPort.readStringUntil( 10 ); // 10 = '\n' Linefeed in ASCII if (in != null) { print("From Arduino: " + in); String[] serialInArray = split(trim(in), ","); if (serialInArray.length == NUM_OF_VALUES_FROM_ARDUINO) { for (int i=0; i<serialInArray.length; i++) { arduino_values[i] = int(serialInArray[i]); } } } } } void drawButton(float xPosition, float yPosition, float buttonWidth, float bottonHeight, int mode_num, String text) { if (mouseX>= xPosition - 0.5*buttonWidth && mouseX<= xPosition+ 0.5*buttonWidth && mouseY>=yPosition-0.5*bottonHeight && mouseY<= yPosition+0.5*bottonHeight) { strokeWeight(5); fill(#CEAC66); rect(xPosition, yPosition, buttonWidth, bottonHeight); textSize(100); fill(0); text(text, xPosition, yPosition); if (mousePressed) { mode = mode_num; } } else { strokeWeight(5); fill(#CEAC66); rect(xPosition, yPosition, 2*buttonWidth/3, 2*bottonHeight/3, 50); textSize(80); fill(0); text(text, xPosition, yPosition); } }
IMA show version
import processing.video.*; import processing.serial.*; Serial serialPort; int NUM_OF_VALUES_FROM_ARDUINO = 20; int arduino_values[] = new int[NUM_OF_VALUES_FROM_ARDUINO]; int NUM_OF_VIDEO = 20; Movie[] video = new Movie[NUM_OF_VIDEO]; int NUM_OF_IMG = 20; PImage[] images = new PImage[NUM_OF_IMG]; Movie myMovieAngelica; Movie myMovieAtract; Movie myMovieBitterness; Movie myMovieCinnamon; Movie myMovieDew; Movie myMovieDOP; Movie myMovieFirewood; Movie myMovieGinger; Movie myMovieGinseng; Movie myMovieJujube; Movie myMovieJute; Movie myMovieLicorice; Movie myMovieMidS; Movie myMovieMVR; Movie myMoviePR; Movie myMovieScutellaria; Movie myMovieSnow; Movie myMovieSpring; Movie myMovieWolf; Movie myMovieWPG; PImage angelica1; PImage atractylodes1; PImage bitterness; PImage cinnamon; PImage dew; PImage dried_orange_peel; PImage firewood1; PImage ginger; PImage ginseng1; PImage jujube; PImage jute; PImage licorice1; PImage midsummer; PImage milkvetch1; PImage peony1; PImage scutellaria; PImage snow; PImage spring; PImage wolf; PImage wpg; PImage start; void setup() { fullScreen(); // size(2560, 1440, P2D); myMovieAngelica = new Movie(this, "Angelicafinal.mp4"); myMovieAtract = new Movie(this, "Atractylodes1.mov"); myMovieBitterness = new Movie(this, "Bitternessfinal.mp4"); myMovieCinnamon = new Movie(this, "Cinnamonfinal.mp4"); myMovieDew = new Movie(this, "dew.mp4"); myMovieDOP = new Movie(this, "DOP1.mov"); myMovieFirewood = new Movie(this, "Firewoodfinal.mp4"); myMovieGinger = new Movie(this, "Gingerfinal.mp4"); myMovieGinseng = new Movie(this, "Ginsengfinal.mp4"); myMovieJujube = new Movie(this, "Jujubefinal.mp4"); myMovieJute = new Movie(this, "Jutefinal.mp4"); myMovieLicorice = new Movie(this, "Licoricefinal.mp4"); myMovieMidS = new Movie(this, "MidS1.mov"); myMovieMVR = new Movie(this, "MVRfinal.mp4"); myMoviePR = new Movie(this, "PeonyRootfinal.mp4"); myMovieScutellaria = new Movie(this, "Scutellaria1.mov"); myMovieSnow = new Movie(this, "snow.mp4"); myMovieSpring = new Movie(this, "spring.mp4"); myMovieWolf = new Movie(this, "Wolf1.mov"); myMovieWPG = new Movie(this, "WPG1.mov"); video[0] = myMovieAngelica; video[1] = myMovieAtract; video[2] = myMovieBitterness; video[3] = myMovieCinnamon; video[4] = myMovieDew; video[5] = myMovieDOP; video[6] = myMovieFirewood; video[7] = myMovieGinger; video[8] = myMovieGinseng; video[9] = myMovieJujube; video[10] = myMovieJute; video[11] = myMovieLicorice; video[12] = myMovieMidS; video[13] = myMovieMVR; video[14] = myMoviePR; video[15] = myMovieScutellaria; video[16] = myMovieSnow; video[17] = myMovieSpring; video[18] = myMovieWolf; video[19] = myMovieWPG; angelica1 = loadImage("Angelica_BZYQ.png"); atractylodes1 = loadImage("Atrac_BZYQ.png"); bitterness = loadImage("bitter.png"); cinnamon = loadImage("cinnamon.png"); dew = loadImage("dew.png"); dried_orange_peel = loadImage("DOP.png"); firewood1 = loadImage("FW_BZYQ.png"); ginger = loadImage("Ginger.png"); ginseng1 = loadImage("Ginseng_BZYQ.png"); jujube = loadImage("jujube.png"); jute = loadImage("Jute.png"); licorice1 = loadImage("Licorice_BZYQ.png"); midsummer = loadImage("Mid_sum.png"); milkvetch1 = loadImage("MVR_BZYQ.png"); peony1 = loadImage("PR_guizhi.png"); scutellaria = loadImage("Scute.png"); snow = loadImage("snow.png"); spring = loadImage("spring.png"); wolf = loadImage("Wolf.png"); wpg = loadImage("WPG.png"); start = loadImage("start_back.jpg"); images[0]= angelica1; images[1]= atractylodes1; images[2]= bitterness; images[3] = cinnamon; images[4]= dew; images[5]= dried_orange_peel; images[6]= firewood1; images[7]= ginger; images[8]= ginseng1; images[9]= jujube; images[10]= jute; images[11]= licorice1; images[12]= midsummer; images[13]= milkvetch1; images[14]= peony1; images[15]= scutellaria; images[16]= snow; images[17]= spring; images[18]= wolf; images[19]= wpg; imageMode(CENTER); printArray(Serial.list()); serialPort = new Serial(this, "COM5", 9600); } void draw() { background(start); getSerialData(); for (int i = 0; i<20; i++) { if (arduino_values[i] ==1 ) { if (video[i].available()) { video[i].read(); } video[i].play(); image(video[i], width/2, height/2); image(images[i], 1754/4.8, 1240/4.8, 1754/2.4, 1240/2.4 ); } else { video[i].pause(); } } } void getSerialData() { while (serialPort.available() > 0) { String in = serialPort.readStringUntil( 10 ); // 10 = '\n' Linefeed in ASCII if (in != null) { print("From Arduino: " + in); String[] serialInArray = split(trim(in), ","); if (serialInArray.length == NUM_OF_VALUES_FROM_ARDUINO) { for (int i=0; i<serialInArray.length; i++) { arduino_values[i] = int(serialInArray[i]); } } } } }