浏览代码

finished logic routine

Toby Chui 9 月之前
父节点
当前提交
c0119e38eb
共有 59 个文件被更改,包括 280 次插入33 次删除
  1. 6 0
      firmware/cute_useless_robot/animation.ino
  2. 5 3
      firmware/cute_useless_robot/cute_useless_robot.ino
  3. 78 5
      firmware/cute_useless_robot/logics.ino
  4. 1 1
      firmware/cute_useless_robot/servo.ino
  5. 8 10
      firmware/cute_useless_robot/tasks.ino
  6. 二进制
      lasercut/lockfile.lck
  7. 二进制
      lasercut/~all-parts_v1.dwg.12000.tmp
  8. 0 0
      sd_card/anime/e0.bin
  9. 二进制
      sd_card/anime/e1.bin
  10. 二进制
      sd_card/anime/y0.bin
  11. 二进制
      sd_card/anime/y1.bin
  12. 二进制
      sd_card/anime/y10.bin
  13. 二进制
      sd_card/anime/y11.bin
  14. 二进制
      sd_card/anime/y12.bin
  15. 二进制
      sd_card/anime/y13.bin
  16. 二进制
      sd_card/anime/y14.bin
  17. 二进制
      sd_card/anime/y15.bin
  18. 二进制
      sd_card/anime/y16.bin
  19. 二进制
      sd_card/anime/y17.bin
  20. 二进制
      sd_card/anime/y18.bin
  21. 二进制
      sd_card/anime/y19.bin
  22. 二进制
      sd_card/anime/y2.bin
  23. 二进制
      sd_card/anime/y20.bin
  24. 二进制
      sd_card/anime/y21.bin
  25. 二进制
      sd_card/anime/y22.bin
  26. 二进制
      sd_card/anime/y23.bin
  27. 二进制
      sd_card/anime/y24.bin
  28. 二进制
      sd_card/anime/y25.bin
  29. 二进制
      sd_card/anime/y26.bin
  30. 二进制
      sd_card/anime/y27.bin
  31. 二进制
      sd_card/anime/y28.bin
  32. 二进制
      sd_card/anime/y29.bin
  33. 二进制
      sd_card/anime/y3.bin
  34. 二进制
      sd_card/anime/y30.bin
  35. 二进制
      sd_card/anime/y31.bin
  36. 二进制
      sd_card/anime/y32.bin
  37. 二进制
      sd_card/anime/y33.bin
  38. 二进制
      sd_card/anime/y34.bin
  39. 二进制
      sd_card/anime/y35.bin
  40. 二进制
      sd_card/anime/y36.bin
  41. 二进制
      sd_card/anime/y37.bin
  42. 二进制
      sd_card/anime/y38.bin
  43. 1 0
      sd_card/anime/y39.bin
  44. 二进制
      sd_card/anime/y4.bin
  45. 1 0
      sd_card/anime/y40.bin
  46. 1 0
      sd_card/anime/y41.bin
  47. 1 0
      sd_card/anime/y42.bin
  48. 1 0
      sd_card/anime/y43.bin
  49. 1 0
      sd_card/anime/y44.bin
  50. 1 0
      sd_card/anime/y45.bin
  51. 1 0
      sd_card/anime/y46.bin
  52. 二进制
      sd_card/anime/y5.bin
  53. 二进制
      sd_card/anime/y6.bin
  54. 二进制
      sd_card/anime/y7.bin
  55. 二进制
      sd_card/anime/y8.bin
  56. 二进制
      sd_card/anime/y9.bin
  57. 69 1
      sd_card/web/animator.html
  58. 85 13
      sd_card/web/index.html
  59. 20 0
      sd_card/web/main.css

+ 6 - 0
firmware/cute_useless_robot/animation.ino

@@ -65,6 +65,12 @@ int getFrameDuration(char anicode, int framecount) {
       return 3000;
     }
     return 300;
+  }else if (anicode == 'y'){
+    //Transits, total duration = 3000ms
+    if (framecount == 46) {
+      return 2540;
+    }
+    return 1;
   }
   return 500;
 }

+ 5 - 3
firmware/cute_useless_robot/cute_useless_robot.ino

@@ -8,6 +8,8 @@
     Board Settings:
     ESP32 v2.014
     -> ESP32 Dev Module
+    -> CPU Freq: 240Mhz
+    -> Arduino & Events run on: Core 1
     -> Flash Mode: DIO
 */
 
@@ -42,9 +44,9 @@
 
 /* WiFI AP Settings */
 #define AP_SSID "(´・ω・`)"
-#define ENABLE_WIFI_DEBUG true  //Set to true to use WiFi Client mode for remote debugging
-#define DEBUG_SSID "LENS"       //Debug SSID, usually your home WiFi SSID
-#define DEBUG_PWD "1a21b998f4"  //Debug Password, your home WiFi Password
+#define ENABLE_WIFI_DEBUG false //Set to true to use WiFi Client mode for remote debugging
+#define DEBUG_SSID "" //Debug SSID, usually your home WiFi SSID
+#define DEBUG_PWD "" //Debug Password, your home WiFi Password
 AsyncWebServer server(80);
 DNSServer dnsServer;
 

+ 78 - 5
firmware/cute_useless_robot/logics.ino

@@ -13,7 +13,7 @@ void executePushAnimationSequence(int seqID) {
     setAnimationCode('a');
     delay(4000);
     pushSwitchDelayed(1000, 1000);
-    if (seqID == 2){
+    if (seqID == 2) {
       //Do not turn off display
       return;
     }
@@ -66,14 +66,87 @@ void executePushAnimationSequence(int seqID) {
     delay(2000);
     setAnimationCode('g');
     return;
+  } else if (seqID < 13) {
+    //Annoyed fast push back
+    setAnimationCode('g');
+    delay(500);
+    pushSwitchNow();
+    delay(1000);
+    return;
+  } else if (seqID < 14) {
+    //Angry & Movement
+    setAnimationCode('y');
+    delay(5000);
+    setAnimationCode('c');
+    delay(2000);
+    servoCoverPusher.write(90);
+    delay(1000);
+    forward(100);
+    backward(100);
+    forward(100);
+    backward(100);
+    pushSwitchNow();
+    return;
+  } else if (seqID < 17) {
+    //Angry fast push
+    delay(500);
+    if (seqID % 2 == 0) {
+      forward(100);
+    } else {
+      backward(100);
+    }
+    pushSwitchNow();
+    delay(1000);
+    return;
+  } else if (seqID < 18) {
+    setAnimationCode('h');
+    delay(1000);
+    setAnimationCode('i');
+    delay(1000);
+    setAnimationCode('j');
+    forward(50);
+    backward(50);
+    forward(50);
+    rotateClockwise(50);
+    rotateAntiClockwise(100);
+    rotateClockwise(100);
+    rotateAntiClockwise(50);
+    pushSwitchDelayed(1000, 300);
+    return;
+  } else if (seqID < 22) {
+    delay(500);
+    pushSwitchDelayed(1000, 300);
+    return;
+  } else if (seqID < 25) {
+    setAnimationCode('d');
+    delay(500);
+    pushWithHesitation();
+    return;
   } else {
     //fallback default push back
-    setAnimationCode('a');
-    delay(4000);
-    pushSwitchDelayed(1000, 1000);
+    delay(500);
+    int expression = random(0, 4);
+    if (expression == 0) {
+      setAnimationCode('a');
+      delay(3000);
+      pushSwitchDelayed(1000, 1000);
+      delay(3000);
+    } else if (expression == 1) {
+      setAnimationCode('b');
+      delay(500);
+      pushSwitchNow();
+    } else if (expression == 2) {
+      setAnimationCode('g');
+      pushWithHesitation();
+      delay(5000);
+    } else {
+      setAnimationCode('e');
+      pushSwitchNow();
+      return;
+    }
   }
   clearFrame();
-  delay(3000);
+  delay(1000);
 }
 
 //Debug sequence to test all movement functions

+ 1 - 1
firmware/cute_useless_robot/servo.ino

@@ -8,7 +8,7 @@
 
 //Quickily push the switch back
 void pushSwitchNow() {
-  pushSwitchDelayed(250, 250);
+  pushSwitchDelayed(270, 270);
 }
 
 //Push switch back with delay

+ 8 - 10
firmware/cute_useless_robot/tasks.ino

@@ -106,18 +106,16 @@ void startCoreTasks() {
     &primaryTask,      /* Task handle to keep track of created task */
     1);
 
-
+  //Pin secondary tasks to core 1 for handling AP movements
   xTaskCreate(
-    SecondaryController,  // Task function
-    "secondary",          // Task name
-    2048,                 // Stack size
-    NULL,                 // Task parameters
-    3,                    // Task priority
-    &secondaryTask        // Task handle
+    SecondaryController,
+    "secondary",
+    2048,
+    NULL, 
+    3,
+    &secondaryTask
   );
-
-
-
+  
   vTaskStartScheduler();
 }
 

二进制
lasercut/lockfile.lck


二进制
lasercut/~all-parts_v1.dwg.12000.tmp


+ 0 - 0
sd_card/anime/e.bin → sd_card/anime/e0.bin


二进制
sd_card/anime/e1.bin


二进制
sd_card/anime/y0.bin


二进制
sd_card/anime/y1.bin


二进制
sd_card/anime/y10.bin


二进制
sd_card/anime/y11.bin


二进制
sd_card/anime/y12.bin


二进制
sd_card/anime/y13.bin


二进制
sd_card/anime/y14.bin


二进制
sd_card/anime/y15.bin


二进制
sd_card/anime/y16.bin


二进制
sd_card/anime/y17.bin


二进制
sd_card/anime/y18.bin


二进制
sd_card/anime/y19.bin


二进制
sd_card/anime/y2.bin


二进制
sd_card/anime/y20.bin


二进制
sd_card/anime/y21.bin


二进制
sd_card/anime/y22.bin


二进制
sd_card/anime/y23.bin


二进制
sd_card/anime/y24.bin


二进制
sd_card/anime/y25.bin


二进制
sd_card/anime/y26.bin


二进制
sd_card/anime/y27.bin


二进制
sd_card/anime/y28.bin


二进制
sd_card/anime/y29.bin


二进制
sd_card/anime/y3.bin


二进制
sd_card/anime/y30.bin


二进制
sd_card/anime/y31.bin


二进制
sd_card/anime/y32.bin


二进制
sd_card/anime/y33.bin


二进制
sd_card/anime/y34.bin


二进制
sd_card/anime/y35.bin


二进制
sd_card/anime/y36.bin


二进制
sd_card/anime/y37.bin


二进制
sd_card/anime/y38.bin


+ 1 - 0
sd_card/anime/y39.bin

@@ -0,0 +1 @@
+���������������������������������������������������������������€

二进制
sd_card/anime/y4.bin


+ 1 - 0
sd_card/anime/y40.bin

@@ -0,0 +1 @@
+�����������������������������������������������������������

+ 1 - 0
sd_card/anime/y41.bin

@@ -0,0 +1 @@
+����������������������������������������������������������������

+ 1 - 0
sd_card/anime/y42.bin

@@ -0,0 +1 @@
+����������������������������������������������������������������

+ 1 - 0
sd_card/anime/y43.bin

@@ -0,0 +1 @@
+����������������������������������������������������������������

+ 1 - 0
sd_card/anime/y44.bin

@@ -0,0 +1 @@
+����������������������������������������������������������������

+ 1 - 0
sd_card/anime/y45.bin

@@ -0,0 +1 @@
+����������������������������������������������������������������

+ 1 - 0
sd_card/anime/y46.bin

@@ -0,0 +1 @@
+����������������������������������������������������������������

二进制
sd_card/anime/y5.bin


二进制
sd_card/anime/y6.bin


二进制
sd_card/anime/y7.bin


二进制
sd_card/anime/y8.bin


二进制
sd_card/anime/y9.bin


+ 69 - 1
sd_card/web/animator.html

@@ -153,6 +153,7 @@
 				<button onclick="loadDefault();">Load Default</button>
 				<button onclick="downloadBinary();">Export Binary</button>
 				<button onclick="openFilePicker()">Import Binary</button>
+				<button onclick="saveToSD();">Save to SD</button>
 				<button onclick="exit()">Back</button>
 				<input type="file" id="fileInput" style="display: none;" accept=".bin" onchange="handleFile(event)">
 			</div>
@@ -171,7 +172,8 @@
 	</div>
     <script>
 		let defaultTemplate = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,0,0,0,1,1,0,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,1,1,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,1,1,0,0,0,1,0,0,1,0,0,1,0,0,0,0,1,1,1,1,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
-		
+		let previousSaveSDName = "";
+
         function generateCircleGrid(containerId) {
             const container = document.getElementById(containerId);
             if (!container) {
@@ -340,6 +342,72 @@
 			updateRWD();
 		})
 
+		function saveToSD(){
+			let anicode = prompt("Emoji animation code (1 char + 1 digit only, e.g. \"k0\")", previousSaveSDName);
+			if (anicode != null) {
+				previousSaveSDName = anicode;
+				const bitArray = getFrameAsIntArray();
+				const byteArray = [];
+				for (let i = 0; i < bitArray.length; i += 8) {
+					let byte = 0;
+					for (let j = 0; j < 8; j++) {
+						if (bitArray[i + j]) {
+							byte |= 1 << (7 - j);
+						}
+					}
+					byteArray.push(byte);
+				}
+
+				const blob = new Blob([new Uint8Array(byteArray)], { type: 'application/octet-stream' });
+				const anifile = new File([blob], anicode + ".bin");
+				uploadFiles([anifile])
+			} 
+		}
+
+		//Upload file to server
+		function uploadFiles(files) {
+            if (files.length === 0) {
+                alert('No files selected.');
+                return;
+            }
+
+            // Create a FormData object to send files as multipart/form-data
+            var formData = new FormData();
+
+            // Append each file to the FormData object
+            for (var i = 0; i < files.length; i++) {
+                formData.append('files[]', files[i]);
+            }
+
+            // Send the FormData object via XMLHttpRequest
+            var xhr = new XMLHttpRequest();
+            xhr.open('POST', '/upload?dir=/anime', true); // Replace '/upload' with your ESP32 server endpoint
+   
+            // Track upload progress
+            xhr.upload.addEventListener('progress', function(event) {
+                if (event.lengthComputable) {
+                    var percentComplete = (event.loaded / event.total) * 100;
+                    console.log('Upload progress: ' + percentComplete.toFixed(2) + '%');
+                } else {
+                    console.log('Upload progress: unknown');
+                }
+            });
+
+            xhr.onload = function() {
+                if (xhr.status === 200) {
+                    alert('Animation frame saved');
+					$.get(`/api/ctr/emoji?anicode=${previousSaveSDName}`);
+                } else {
+                    alert('Error writing files to disk.');
+                }
+            };
+
+            xhr.onerror = function() {
+                alert('Error uploading files.');
+            };
+            xhr.send(formData);
+        }
+
     </script>
 </body>
 </html>

+ 85 - 13
sd_card/web/index.html

@@ -26,13 +26,14 @@
       <div class="divider"></div>
       <h3>Quick Actions</h3>
       <p>Display Emoji</p>
-      <select class="styled-dropdown">
-        <option value="option1">Option 1</option>
-        <option value="option2">Option 2</option>
-        <option value="option3">Option 3</option>
-        <option value="option4">Option 4</option>
-      </select>
+      <div class="emoji-control">
+        <div id="emojibtns">
+
+        </div>
+        <button onclick="initEmojis();" class="reload button">Reload</button>
+      </div>
       
+
       <!-- Other Actions -->
       <div class="action-controls">
         <button id="coverbtn" class="button">
@@ -81,14 +82,14 @@
         <a class="clickable item" href="animator.html">
           <img src="img/animation.svg"> Animation Editor
         </a>
-        <a class="clickable item" >
+        <!-- <a class="clickable item" >
           <img src="img/action.svg"> Action Programmer
-        </a>
+        </a> -->
         <a class="clickable item" href="sd.html">
           <img src="img/folder.svg"> SD Browser
         </a>
-        <a class="clickable item">
-          <img src="img/code.svg"> Developer Tools
+        <a class="clickable item" onclick="movePusherToInstallPos();">
+          <img src="img/code.svg"> Pusher Install Pos
         </a>
         <div class="item">
           <small>Cute Useless Robot v1.0</small>
@@ -97,6 +98,69 @@
     </div>
   <script>
     let coverOpen = false;
+
+    /* Emoji selection buttons */
+    function initEmojis(){
+      $("#emojibtns").html("");
+      let keyChecker = {};
+      $.get("/api/fs/listDir?dir=anime", function(data){
+        //Sort it alphabetically
+        data.sort(function(a, b) {
+          var keyA = (a.Filename),
+            keyB = (b.Filename);
+          // Compare the 2 dates
+          if (keyA < keyB) return -1;
+          if (keyA > keyB) return 1;
+          return 0;
+        });
+        //Render buttons
+        data.forEach(expression => {
+          let emojiCode = expression.Filename;
+          let anicode = emojiCode.split(".");
+          let ext = anicode.pop();
+          if (ext != "bin"){
+            return;
+          }
+          anicode = anicode[0];
+          let anigroup = anicode.substr(0, 1); //e.g. k0 anigroup is k
+          if (typeof(keyChecker[anigroup]) == 'undefined'){
+            //This group not mapped
+            $("#emojibtns").append(`<button onclick="setExpression('${anigroup}');" class="expressionbtn button" group="${anigroup}" filename="${emojiCode}">${anigroup}</button>`);
+            keyChecker[anigroup] = 0;
+          }else{
+            keyChecker[anigroup]++;
+          }
+        })
+
+        //Render frame count
+        for (const [key, value] of Object.entries(keyChecker)) {
+          let frameName = key;
+          if (frameName == "a"){
+            frameName = "default";
+          }else if (frameName == "w"){
+            frameName = "WiFi";
+          }else if (frameName == "x"){
+            frameName = "WiFi Error";
+          }else if (frameName == "z"){
+            frameName = "Clear";
+          }
+
+          let animationTag = "[Static]";
+          if (value > 0){
+            animationTag = `[${value + 1} frames]`
+          }
+          $(`.expressionbtn[group=${key}]`).text(`${frameName} ${animationTag}`);
+        }
+        
+      })
+    }
+    initEmojis();
+    
+    function setExpression(anigroup){
+      $.get(`/api/ctr/emoji?anicode=${anigroup}`, function(data){
+
+      });
+    }
     /* Action APIS */
     function movePusher(angle=0){
       $.get(`/api/ctr/pusher?angle=${angle}`, function(data){
@@ -104,6 +168,12 @@
       });
     }
 
+    function movePusherToInstallPos(){
+      $.get(`/api/ctr/pusher?angle=120`, function(data){
+
+      });
+    }
+
     function moveCover(open=true){
       $.get(`/api/ctr/cover?state=${open?"open":"close"}`, function(data){
 
@@ -139,14 +209,16 @@
     function pushSwitchStart(event) {
       event.preventDefault();
       console.log('Push Switch Start');
-      movePusher(140);
+      
     }
 
     function pushSwitchEnd(event) {
       event.preventDefault();
       console.log('Push Switch End');
-      // Add your code here
-      movePusher(0);
+      movePusher(140);
+      setTimeout(function(){
+        movePusher(0);
+      }, 1000);
     }
 
     // Direction Controls

+ 20 - 0
sd_card/web/main.css

@@ -204,6 +204,26 @@ a:link {
     color: white;
   }
 
+
+/* Emoji buttons */
+.emoji-control .reload.button{
+    padding: 10px;
+    margin: 5px;
+    background-color: rgb(74, 148, 74);
+    color: white;
+    font-size: 16px;
+}
+
+#emojibtns .expressionbtn{
+    padding: 10px;
+    margin: 5px;
+    background-color: rgb(119, 233, 125);
+    color: white;
+    font-size: 16px;
+    border: none;
+    cursor: pointer;
+}
+
 /* Action Control Buttons */
 .action-controls{
     display: flex;