sneaky4oe

Ladybug Ratmobile Arduino Nano

Oct 4th, 2025 (edited)
450
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.02 KB | Pets | 0 0
  1. /* WORKING BASELINE + smooth ramp for S
  2. (unchanged start logic) + watchdog reset ONLY while moving if no keys ≥500ms
  3. Pins: lMot1 = 6 (PWM), lMot2 = 9, rMot1 = 10, rMot2 = 11
  4. Max speed capped at 180/255 (both ramp and hold)
  5. */
  6.  
  7. #include <avr/io.h>
  8. #include <avr/wdt.h>
  9.  
  10. //// Pins (WASD)
  11. const uint8_t W=5, A=2, S=4, D=3;
  12.  
  13. //// Motors (LEFT inverted)
  14. const uint8_t lMot1=6, lMot2=9; // LEFT (inv) — both PWM
  15. const uint8_t rMot1=10, rMot2=11; // RIGHT
  16.  
  17. //// Timings (baseline)
  18. const unsigned long BACK_MS = 400; // wait before S starts
  19. const unsigned long RAMP_MS_WAD = 700; // ramp for W/A/D
  20. const unsigned long RAMP_MS_S = 700; // ramp for S after delay
  21. const uint8_t RAMP_STEPS = 24;
  22.  
  23. //// Max PWM cap
  24. const uint8_t MAX_DUTY = 180; // limit "full speed" to 180/255
  25.  
  26. //// Helpers
  27. inline bool pressed(uint8_t p){ return digitalRead(p)==LOW; }
  28. inline bool anyPressed(){ return pressed(W)||pressed(A)||pressed(S)||pressed(D); }
  29. inline void halt(){
  30. digitalWrite(lMot1,LOW); digitalWrite(lMot2,LOW);
  31. digitalWrite(rMot1,LOW); digitalWrite(rMot2,LOW);
  32. }
  33.  
  34. // Watchdog: ONLY while moving and no keys ≥500ms
  35. bool moving = false; // true: ramp/hold; false: idle/Back-delay
  36. unsigned long noKeyStart = 0; // when "no key" interval began (only in motion)
  37.  
  38. inline void motionResetTick(){
  39. if(!moving){ noKeyStart = 0; return; }
  40. if(anyPressed()){ noKeyStart = 0; return; }
  41. if(noKeyStart==0) noKeyStart = millis();
  42. else if(millis() - noKeyStart >= 500){
  43. wdt_enable(WDTO_15MS); // force fast reset
  44. while(true){} // wait for watchdog
  45. }
  46. }
  47.  
  48. // Full-power drive by direction: -1=back, 0=stop, +1=fwd
  49. inline void driveFull(int8_t L, int8_t R){
  50. // LEFT (inverted wiring)
  51. if(L>0){ digitalWrite(lMot1,LOW); digitalWrite(lMot2,HIGH); }
  52. else if(L<0){ digitalWrite(lMot1,HIGH); digitalWrite(lMot2,LOW); }
  53. else { digitalWrite(lMot1,LOW); digitalWrite(lMot2,LOW); }
  54. // RIGHT (normal)
  55. if(R>0){ digitalWrite(rMot1,HIGH); digitalWrite(rMot2,LOW); }
  56. else if(R<0){ digitalWrite(rMot1,LOW); digitalWrite(rMot2,HIGH); }
  57. else { digitalWrite(rMot1,LOW); digitalWrite(rMot2,LOW); }
  58. }
  59.  
  60. // One PWM step (HW PWM everywhere now)
  61. inline void drivePWM(int8_t Ldir, int8_t Rdir, uint8_t duty){
  62. if(duty > MAX_DUTY) duty = MAX_DUTY;
  63. // LEFT
  64. if(Ldir>0){ digitalWrite(lMot1,LOW); analogWrite(lMot2,duty); }
  65. else if(Ldir<0){ analogWrite(lMot1,duty); digitalWrite(lMot2,LOW); }
  66. else { digitalWrite(lMot1,LOW); digitalWrite(lMot2,LOW); }
  67. // RIGHT
  68. if(Rdir>0){ analogWrite(rMot1,duty); digitalWrite(rMot2,LOW); }
  69. else if(Rdir<0){ digitalWrite(rMot1,LOW); analogWrite(rMot2,duty); }
  70. else { digitalWrite(rMot1,LOW); digitalWrite(rMot2,LOW); }
  71. }
  72.  
  73. // Blocking ramp (baseline, no mid-checks).
  74. // allowS=false for W/A/D (pressing S during ramp -> abort),
  75. // allowS=true for BACK.
  76. void rampBlocking(int8_t Ldir, int8_t Rdir, unsigned long ramp_ms, uint8_t steps, bool allowS){
  77. moving = true; // in motion during ramp
  78. const unsigned long slice = ramp_ms / steps;
  79. for(uint8_t i=1;i<=steps;i++){
  80. motionResetTick(); // reset only if moving & no keys
  81.  
  82. // Anti-chord during ramp: exactly one key
  83. bool w=pressed(W), a=pressed(A), s=pressed(S), d=pressed(D);
  84. uint8_t n=(w?1:0)+(a?1:0)+(s?1:0)+(d?1:0);
  85. if(n!=1) { halt(); moving=false; return; }
  86. if(!allowS && s){ halt(); moving=false; return; } // S forbidden for W/A/D
  87.  
  88. // soft start scaled to MAX_DUTY (was 25..255; now 25..180)
  89. uint8_t duty = 25 + (uint16_t)((MAX_DUTY - 25) * i) / steps;
  90. drivePWM(Ldir,Rdir,duty);
  91. delay(slice);
  92. }
  93. // After ramp -> hold at capped "full" PWM
  94. drivePWM(Ldir,Rdir,MAX_DUTY);
  95. // keep moving=true (holding speed)
  96. }
  97.  
  98. //// Simple command enum + “run-once ramp” latch
  99. enum Cmd { NONE, FWD, LEFT, BACK, RIGHT };
  100. Cmd lastCmd = NONE;
  101.  
  102. void setup(){
  103. // Robustly disable watchdog left over from previous reset/bootloader
  104. MCUSR &= ~(1<<WDRF);
  105. wdt_disable();
  106.  
  107. pinMode(W,INPUT_PULLUP); pinMode(A,INPUT_PULLUP);
  108. pinMode(S,INPUT_PULLUP); pinMode(D,INPUT_PULLUP);
  109. pinMode(lMot1,OUTPUT); pinMode(lMot2,OUTPUT);
  110. pinMode(rMot1,OUTPUT); pinMode(rMot2,OUTPUT);
  111. halt();
  112. }
  113.  
  114. void loop(){
  115. delay(10);
  116. motionResetTick(); // watch only during motion
  117.  
  118. // Read & anti-chord (baseline)
  119. bool w=pressed(W), a=pressed(A), s=pressed(S), d=pressed(D);
  120. uint8_t n=(w?1:0)+(a?1:0)+(s?1:0)+(d?1:0);
  121.  
  122. if(n!=1){
  123. halt(); lastCmd=NONE;
  124. moving=false; // idle -> no watchdog
  125. return;
  126. }
  127.  
  128. // Map to command
  129. Cmd cmd = w?FWD : a?LEFT : s?BACK : RIGHT;
  130.  
  131. // New command? (edge)
  132. if(cmd != lastCmd){
  133. if(cmd == BACK){
  134. // Blocking start delay (not considered motion)
  135. moving = false;
  136. unsigned long t0 = millis();
  137. while(millis()-t0 < BACK_MS){
  138. // Abort if not exactly S
  139. bool w2=pressed(W), a2=pressed(A), s2=pressed(S), d2=pressed(D);
  140. uint8_t n2=(w2?1:0)+(a2?1:0)+(s2?1:0)+(d2?1:0);
  141. if(n2!=1 || !s2){ halt(); lastCmd=NONE; return; }
  142. halt(); // stand still during delay
  143. }
  144. // Smooth ramp backward (allowS=true)
  145. rampBlocking(-1,-1, RAMP_MS_S, RAMP_STEPS, /*allowS=*/true);
  146. lastCmd = BACK;
  147. return;
  148. }
  149.  
  150. // W/A/D: single smooth ramp then hold (allowS=false)
  151. if(cmd == FWD) rampBlocking(+1,+1, RAMP_MS_WAD, RAMP_STEPS, /*allowS=*/false);
  152. if(cmd == LEFT) rampBlocking(-1,+1, RAMP_MS_WAD, RAMP_STEPS, /*allowS=*/false);
  153. if(cmd == RIGHT)rampBlocking(+1,-1, RAMP_MS_WAD, RAMP_STEPS, /*allowS=*/false);
  154.  
  155. lastCmd = cmd;
  156. return;
  157. }
  158.  
  159. // Same command continues: hold steady at capped PWM instead of raw full-bridge
  160. if(cmd == FWD) drivePWM(+1,+1, MAX_DUTY);
  161. if(cmd == LEFT) drivePWM(-1,+1, MAX_DUTY);
  162. if(cmd == RIGHT) drivePWM(+1,-1, MAX_DUTY);
  163. if(cmd == BACK) drivePWM(-1,-1, MAX_DUTY);
  164. moving = true; // holding = motion
  165. }
  166.  
Advertisement
Add Comment
Please, Sign In to add comment