瀏覽代碼

Added animation core code

Toby Chui 10 月之前
父節點
當前提交
a34dceb405

+ 51 - 0
firmware/cute_useless_robot/animation.ino

@@ -0,0 +1,51 @@
+/* Animation Rendering Logics */
+
+int frameCount = 0;
+char previousAnicode = 'a';
+
+//Handle animation rendering
+void handleAnimationRendering(char anicode) {
+  if (previousAnicode != anicode){
+    previousAnicode = anicode;
+    frameCount = 0;
+  }
+  //Check if the target animation frame is static
+  String targetFrame = "/" + String(anicode) + ".bin";
+  if (SD.exists(targetFrame)) {
+    //This is a static frame. Load and render it
+    loadFrameAndRender(targetFrame);
+    delay(getFrameDuration(anicode,0));
+    return;
+  }
+
+  //It is not a static frame. Check if x0.bin exists
+  targetFrame = "/" + String(anicode) + String(frameCount) + ".bin";
+  if (SD.exists(targetFrame)) {
+    loadFrameAndRender(targetFrame);
+    frameCount++;
+    delay(getFrameDuration(anicode,frameCount));
+    return;
+  } else {
+    //Not found.
+    if (frameCount != 0) {
+      loadFrameAndRender("/" + String(anicode) + "0.bin");
+      delay(getFrameDuration(anicode,0));
+      frameCount = 1;
+      return;
+    } else {
+      //frameCount = 0. x0.bin not exists. Report error
+      Serial.println("Target frame buffer not found: " + String(anicode) + ".bin");
+      setAnimationCode('a');
+      return;
+    }
+  }
+}
+
+//Get how long the frame shd last. 
+//Default 500 unless specially programmed
+int getFrameDuration(char anicode, int framecount){
+  if ((anicode == 'a' || anicode == 'b') && framecount == 0){
+    return 4000;
+  }
+  return 500;
+}

+ 16 - 28
firmware/cute_useless_robot/cute_useless_robot.ino

@@ -36,54 +36,42 @@ Servo servoSwitchPusher;
 Servo servoCoverPusher;
 MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, DP_DATA_PIN, DP_CLK_PIN, DP_CS_PIN, MAX_DEVICES);
 
+/* Global Variables */
+char animation = 'a'; //Animation ID to render
+
 void setup() {
   Serial.begin(115200);
-  
+
   /* Stepper IO */
   pinMode(STP_DATA_PIN, OUTPUT);
   pinMode(STP_CLOCK_PIN, OUTPUT);
   pinMode(STP_LATCH_PIN, OUTPUT);
   standbySteppers();
-  
+
   /* Servo IO */
   servoSwitchPusher.attach(SERVO_SWITCH);
   servoCoverPusher.attach(SERVO_COVER);
+  servoCoverPusher.write(0);
+  servoSwitchPusher.write(0);
+
   /* SD Card */
   // Initialize SD card
   if (!SD.begin(SD_CS_PIN)) {
     Serial.println("[Error] Unable to mount SD card");
   }
-  
+
   /* Display Module */
   mx.begin();
   setDisplayBrightness(0x4);
-  renderFrame();
+  renderFrame(); //Render the default frame to matrix
   delay(5000);
+
+  /* Start Dual-core processes */
+  createSemaphore();
+  startCoreTasks();
 }
 
 void loop() {
-  //Stepper test
-  forward(50);
-  delay(3000);
-  backward(50);
-  delay(3000);
-  rotateAntiClockwise(100);
-  delay(1000);
-  //blink
-  loadAndRender("/b.bin");
-  delay(500);
-  loadAndRender("/a.bin");
-  delay(2000);
-  //rotate backward
-  rotateClockwise(100);
-  delay(3000);
-  //Servo test
-  servoCoverPusher.write(90);
-  delay(1000);
-  servoSwitchPusher.write(180);
-  delay(1000);
-  servoCoverPusher.write(0);
-  servoSwitchPusher.write(0);
-  delay(3000);
-  
+  //Process has been handled in tasks.ino
+  //Do not use this loop
 }

+ 2 - 2
firmware/cute_useless_robot/display.ino

@@ -29,8 +29,8 @@ unsigned char frame_buffer[] = {
 };
 
 //A combined function for read frame to framebuffer and render to display
-//Example usage: loadAndRender("/a.bin");
-void loadAndRender(String filepath){
+//Example usage: loadFrameAndRender("/a.bin");
+void loadFrameAndRender(String filepath){
   readFrameToFrameBuffer(filepath);
   renderFrame();
 }

+ 8 - 4
firmware/cute_useless_robot/stepper.ino

@@ -1,7 +1,7 @@
 /* Stepper Drivers Functions */
 
 //writeStep write the step given the byte representation of a step on both stepper
-//e.g. writeStep(0b00110011); 
+//e.g. writeStep(0b00110011);
 void writeStep(byte stepByte) {
   shiftOut(STP_DATA_PIN, STP_CLOCK_PIN, MSBFIRST, stepByte);
   digitalWrite(STP_LATCH_PIN, HIGH);
@@ -11,11 +11,11 @@ void writeStep(byte stepByte) {
 
 //Set all coils to off and enter standby mode
 //to save power and prevent overheating
-void standbySteppers(){
+void standbySteppers() {
   writeStep(0b00000000);
 }
 
-//Move the robot forward by 8 * rev micro steps 
+//Move the robot forward by 8 * rev micro steps
 void forward(int rev) {
   for (int i = 0; i < rev; i++) {
     writeStep(0b00010001);
@@ -27,9 +27,10 @@ void forward(int rev) {
     writeStep(0b10001000);
     writeStep(0b10011001);
   }
+  standbySteppers();
 }
 
-//Move the robot backward by 8 * rev micro steps 
+//Move the robot backward by 8 * rev micro steps
 void backward(int rev) {
   for (int i = 0; i < rev; i++) {
     writeStep(0b10011001);
@@ -41,6 +42,7 @@ void backward(int rev) {
     writeStep(0b00110011);
     writeStep(0b00010001);
   }
+  standbySteppers();
 }
 
 //Differential offset the robot wheels by +- 8 * rev micro steps, anti-clockwise
@@ -55,6 +57,7 @@ void rotateAntiClockwise(int rev) {
     writeStep(0b10000011);
     writeStep(0b10010001);
   }
+  standbySteppers();
 }
 
 //Differential offset the robot wheels by +- 8 * rev micro steps, clockwise
@@ -69,4 +72,5 @@ void rotateClockwise(int rev) {
     writeStep(0b00111000);
     writeStep(0b00011001);
   }
+  standbySteppers();
 }

+ 113 - 0
firmware/cute_useless_robot/tasks.ino

@@ -0,0 +1,113 @@
+/* Multi-core Task Handler*/
+TaskHandle_t primaryTask;
+TaskHandle_t animationTask;
+SemaphoreHandle_t animationMutex;
+
+/* Semaphore for handling mutex */
+void createSemaphore() {
+  animationMutex = xSemaphoreCreateMutex();
+  xSemaphoreGive(animationMutex);
+}
+
+void mutexLock() {
+  xSemaphoreTake(animationMutex, portMAX_DELAY);
+}
+
+void mutexUnlock() {
+  xSemaphoreGive(animationMutex);
+}
+
+//Set the animation code, suppose to be used in core 0 only
+void setAnimationCode(char filename) {
+  Serial.println("Updating animation frame to " + String(filename));
+  mutexLock();
+  animation = filename;
+  mutexUnlock();
+}
+
+//Get the animation code, suppose to be used in core 1 only
+char getAnimationCode() {
+  char anicode = 'a';
+  mutexLock();
+  anicode = animation;
+  mutexUnlock();
+  return anicode;
+}
+
+
+/* Multi-core process definations */
+void startCoreTasks() {
+  //core 1
+  xTaskCreatePinnedToCore(
+    AnimationController,   /* Task function. */
+    "animator",     /* name of task. */
+    10000,       /* Stack size of task */
+    NULL,        /* parameter of the task */
+    1,           /* priority of the task */
+    &animationTask,      /* Task handle to keep track of created task */
+    1
+  );
+  delay(500);
+  
+  //core 0
+  xTaskCreatePinnedToCore(
+    PrimaryController,   /* Task function. */
+    "primary",     /* name of task. */
+    10000,       /* Stack size of task */
+    NULL,        /* parameter of the task */
+    1,           /* priority of the task */
+    &primaryTask,      /* Task handle to keep track of created task */
+    0
+  );          /* pin task to core 0 */
+}
+
+//Core 0 code, for movement and primary logics
+void PrimaryController( void * pvParameters ) {
+  Serial.println("Primary logic process started on core " + String(xPortGetCoreID()));
+  for (;;) {
+    //Loop of primary logics
+    setAnimationCode('a');
+    delay(30000);
+    //setAnimationCode('c');
+    //delay(5000);
+    setAnimationCode('j');
+    delay(30000);
+
+
+    //Stepper test
+    /*
+      forward(50);
+      delay(3000);
+      backward(50);
+      delay(3000);
+      rotateAntiClockwise(100);
+      delay(1000);
+
+      //blink
+      loadAndRender("/b.bin");
+      delay(300);
+      loadAndRender("/a.bin");
+      delay(2000);
+      //rotate backward
+      rotateClockwise(100);
+      delay(3000);
+      //Servo test
+      servoCoverPusher.write(90);
+      delay(1000);
+      servoSwitchPusher.write(180);
+      delay(1000);
+      servoCoverPusher.write(0);
+      servoSwitchPusher.write(0);
+      delay(3000);
+    */
+  }
+}
+
+//Core 1 code, for animation rendering
+void AnimationController( void * pvParameters ) {
+  Serial.println("Animation render started on core " + String(xPortGetCoreID()));
+  for (;;) {
+    char anicode = getAnimationCode();
+    handleAnimationRendering(anicode);
+  }
+}

二進制
sd_card/anime/a0.bin


二進制
sd_card/anime/a1.bin


二進制
sd_card/anime/a2.bin


二進制
sd_card/anime/b0.bin


二進制
sd_card/anime/b1.bin


二進制
sd_card/anime/b2.bin


二進制
sd_card/anime/j0.bin


二進制
sd_card/anime/j1.bin


二進制
sd_card/anime/j2.bin


二進制
sd_card/anime/j3.bin


二進制
sd_card/anime/j4.bin