Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* WORKING BASELINE + smooth ramp for S
- (unchanged start logic) + watchdog reset ONLY while moving if no keys ≥500ms
- Pins: lMot1 = 6 (PWM), lMot2 = 9, rMot1 = 10, rMot2 = 11
- Max speed capped at 180/255 (both ramp and hold)
- */
- #include <avr/io.h>
- #include <avr/wdt.h>
- //// Pins (WASD)
- const uint8_t W=5, A=2, S=4, D=3;
- //// Motors (LEFT inverted)
- const uint8_t lMot1=6, lMot2=9; // LEFT (inv) — both PWM
- const uint8_t rMot1=10, rMot2=11; // RIGHT
- //// Timings (baseline)
- const unsigned long BACK_MS = 400; // wait before S starts
- const unsigned long RAMP_MS_WAD = 700; // ramp for W/A/D
- const unsigned long RAMP_MS_S = 700; // ramp for S after delay
- const uint8_t RAMP_STEPS = 24;
- //// Max PWM cap
- const uint8_t MAX_DUTY = 180; // limit "full speed" to 180/255
- //// Helpers
- inline bool pressed(uint8_t p){ return digitalRead(p)==LOW; }
- inline bool anyPressed(){ return pressed(W)||pressed(A)||pressed(S)||pressed(D); }
- inline void halt(){
- digitalWrite(lMot1,LOW); digitalWrite(lMot2,LOW);
- digitalWrite(rMot1,LOW); digitalWrite(rMot2,LOW);
- }
- // Watchdog: ONLY while moving and no keys ≥500ms
- bool moving = false; // true: ramp/hold; false: idle/Back-delay
- unsigned long noKeyStart = 0; // when "no key" interval began (only in motion)
- inline void motionResetTick(){
- if(!moving){ noKeyStart = 0; return; }
- if(anyPressed()){ noKeyStart = 0; return; }
- if(noKeyStart==0) noKeyStart = millis();
- else if(millis() - noKeyStart >= 500){
- wdt_enable(WDTO_15MS); // force fast reset
- while(true){} // wait for watchdog
- }
- }
- // Full-power drive by direction: -1=back, 0=stop, +1=fwd
- inline void driveFull(int8_t L, int8_t R){
- // LEFT (inverted wiring)
- if(L>0){ digitalWrite(lMot1,LOW); digitalWrite(lMot2,HIGH); }
- else if(L<0){ digitalWrite(lMot1,HIGH); digitalWrite(lMot2,LOW); }
- else { digitalWrite(lMot1,LOW); digitalWrite(lMot2,LOW); }
- // RIGHT (normal)
- if(R>0){ digitalWrite(rMot1,HIGH); digitalWrite(rMot2,LOW); }
- else if(R<0){ digitalWrite(rMot1,LOW); digitalWrite(rMot2,HIGH); }
- else { digitalWrite(rMot1,LOW); digitalWrite(rMot2,LOW); }
- }
- // One PWM step (HW PWM everywhere now)
- inline void drivePWM(int8_t Ldir, int8_t Rdir, uint8_t duty){
- if(duty > MAX_DUTY) duty = MAX_DUTY;
- // LEFT
- if(Ldir>0){ digitalWrite(lMot1,LOW); analogWrite(lMot2,duty); }
- else if(Ldir<0){ analogWrite(lMot1,duty); digitalWrite(lMot2,LOW); }
- else { digitalWrite(lMot1,LOW); digitalWrite(lMot2,LOW); }
- // RIGHT
- if(Rdir>0){ analogWrite(rMot1,duty); digitalWrite(rMot2,LOW); }
- else if(Rdir<0){ digitalWrite(rMot1,LOW); analogWrite(rMot2,duty); }
- else { digitalWrite(rMot1,LOW); digitalWrite(rMot2,LOW); }
- }
- // Blocking ramp (baseline, no mid-checks).
- // allowS=false for W/A/D (pressing S during ramp -> abort),
- // allowS=true for BACK.
- void rampBlocking(int8_t Ldir, int8_t Rdir, unsigned long ramp_ms, uint8_t steps, bool allowS){
- moving = true; // in motion during ramp
- const unsigned long slice = ramp_ms / steps;
- for(uint8_t i=1;i<=steps;i++){
- motionResetTick(); // reset only if moving & no keys
- // Anti-chord during ramp: exactly one key
- bool w=pressed(W), a=pressed(A), s=pressed(S), d=pressed(D);
- uint8_t n=(w?1:0)+(a?1:0)+(s?1:0)+(d?1:0);
- if(n!=1) { halt(); moving=false; return; }
- if(!allowS && s){ halt(); moving=false; return; } // S forbidden for W/A/D
- // soft start scaled to MAX_DUTY (was 25..255; now 25..180)
- uint8_t duty = 25 + (uint16_t)((MAX_DUTY - 25) * i) / steps;
- drivePWM(Ldir,Rdir,duty);
- delay(slice);
- }
- // After ramp -> hold at capped "full" PWM
- drivePWM(Ldir,Rdir,MAX_DUTY);
- // keep moving=true (holding speed)
- }
- //// Simple command enum + “run-once ramp” latch
- enum Cmd { NONE, FWD, LEFT, BACK, RIGHT };
- Cmd lastCmd = NONE;
- void setup(){
- // Robustly disable watchdog left over from previous reset/bootloader
- MCUSR &= ~(1<<WDRF);
- wdt_disable();
- pinMode(W,INPUT_PULLUP); pinMode(A,INPUT_PULLUP);
- pinMode(S,INPUT_PULLUP); pinMode(D,INPUT_PULLUP);
- pinMode(lMot1,OUTPUT); pinMode(lMot2,OUTPUT);
- pinMode(rMot1,OUTPUT); pinMode(rMot2,OUTPUT);
- halt();
- }
- void loop(){
- delay(10);
- motionResetTick(); // watch only during motion
- // Read & anti-chord (baseline)
- bool w=pressed(W), a=pressed(A), s=pressed(S), d=pressed(D);
- uint8_t n=(w?1:0)+(a?1:0)+(s?1:0)+(d?1:0);
- if(n!=1){
- halt(); lastCmd=NONE;
- moving=false; // idle -> no watchdog
- return;
- }
- // Map to command
- Cmd cmd = w?FWD : a?LEFT : s?BACK : RIGHT;
- // New command? (edge)
- if(cmd != lastCmd){
- if(cmd == BACK){
- // Blocking start delay (not considered motion)
- moving = false;
- unsigned long t0 = millis();
- while(millis()-t0 < BACK_MS){
- // Abort if not exactly S
- bool w2=pressed(W), a2=pressed(A), s2=pressed(S), d2=pressed(D);
- uint8_t n2=(w2?1:0)+(a2?1:0)+(s2?1:0)+(d2?1:0);
- if(n2!=1 || !s2){ halt(); lastCmd=NONE; return; }
- halt(); // stand still during delay
- }
- // Smooth ramp backward (allowS=true)
- rampBlocking(-1,-1, RAMP_MS_S, RAMP_STEPS, /*allowS=*/true);
- lastCmd = BACK;
- return;
- }
- // W/A/D: single smooth ramp then hold (allowS=false)
- if(cmd == FWD) rampBlocking(+1,+1, RAMP_MS_WAD, RAMP_STEPS, /*allowS=*/false);
- if(cmd == LEFT) rampBlocking(-1,+1, RAMP_MS_WAD, RAMP_STEPS, /*allowS=*/false);
- if(cmd == RIGHT)rampBlocking(+1,-1, RAMP_MS_WAD, RAMP_STEPS, /*allowS=*/false);
- lastCmd = cmd;
- return;
- }
- // Same command continues: hold steady at capped PWM instead of raw full-bridge
- if(cmd == FWD) drivePWM(+1,+1, MAX_DUTY);
- if(cmd == LEFT) drivePWM(-1,+1, MAX_DUTY);
- if(cmd == RIGHT) drivePWM(+1,-1, MAX_DUTY);
- if(cmd == BACK) drivePWM(-1,-1, MAX_DUTY);
- moving = true; // holding = motion
- }
Advertisement
Add Comment
Please, Sign In to add comment