I have a problem with the Arduino Motor Shield R3 on an Arduino Uno. I Have a DC Motor on the A Channel and the Shield is connected to an external power source. When I reset the Arduino card the motor starts running by default until the pins are initialized.
This is really problematic for me because the motor is on a rail delimited by 2 switches, when a switch is reached the motor stops. When the motor moves during reset the value of the switches are not read yet, which causes the motor to go beyond the switch and be blocked afterwards.
When I reset the card I read the value of the 3 digital pins used to drive the motor :
- pin 12 : Direction (DirA), HIGH motor foward, LOW motor running backward
- pin 3 : Power (PwmA), HIGH motor running, LOW motor not running
- pin 9 : Brake (BrakeA), HIGH brake is on, motor can't run, LOW brake is off, motor can run
Before reseting I put the 3 pins at HIGH, At reset, pin 12 == HIGH, pin 9 == LOW, pin 3 == HIGH which means that the brake is disengaged but the Power is still here, so the motor starts running again until the pinMode function is reached. During that reset time of approximately 2 seconds, the motor has the time to go beyond the switches which causes the system to break.
Is this normal ? Is there a way to force the pin 3 to be at LOW when the Arduino resets ? I put my code at the bottom.
Naïve solution : is to put PwmA at LOW when a switch is reached, so I'm sure it will stay that way until the next reset. But if the arduino is reseted while the motor is running I still have the problem.
int closeSwitch = A3;
int openSwitch = A2;
int DirA = 12;
int PwmA = 3;
int BrakeA = 9;
int OpeningDirection = LOW;
int ClosingDirection = HIGH;
bool motorRunning = false;
bool motorOpening = false;
bool openSwitchReached = false;
bool closeSwitchReached = false;
void setup() {
Serial.begin(9600);
sendToPC("Init\n"); //This is just to read the init state of the pins
Serial.print(digitalRead(DirA));
Serial.print(digitalRead(BrakeA));
Serial.print(digitalRead(PwmA));
pinMode(openSwitch, INPUT);//is High when Hublot opened
pinMode(closeSwitch, INPUT); //is HIGH when hublot closed
pinMode(DirA, OUTPUT); //Initiates Motor Channel A pin
pinMode(BrakeA, OUTPUT); //Initiates Brake Channel A pin
pinMode(PwmA, OUTPUT); //Initiates Brake Channel A pin
sendToPC("\nAfter\nA:"); //After init all is LOW
Serial.print(digitalRead(DirA));
Serial.print(digitalRead(BrakeA));
Serial.print(digitalRead(PwmA));
//Stopping the motor
setMotorSpeed(0);
if (digitalRead(BrakeA) == LOW) {
brakeMotor();
}
//Is the first switch on
openSwitchReached = (digitalRead(openSwitch) == HIGH);
//Second switch state
closeSwitchReached = (digitalRead(closeSwitch) == HIGH);
handleSerialInput(-3); //Send ping return
handleSerialInput(-2); //Send status
}
void sendToPC(const char * str) {
Serial.write(str);
delay(215); //Delay to avoid answers being read as one
}
void setMotorSpeed(int speed) {
if (speed > 0)
digitalWrite(BrakeA, LOW); //Disengage the Brake for Channel A
digitalWrite(PwmA, HIGH); //Spins the motor on Channel A at full speed
}
void setMotorDirection(int direction) {
digitalWrite(DirA, direction); //Establishes direction of Channel A
}
void brakeMotor() {
digitalWrite(BrakeA, HIGH);
//digitalWrite(PwmA, LOW); -> this is my naïve solution
}
void handleSerialInput(int input) {
Serial.print(input);
if (input == 1 && !openSwitchReached) { //open
brakeMotor(); // stop motor
delay(100);
setMotorDirection(OpeningDirection);
setMotorSpeed(255); // set motor max speed
motorRunning = true;
motorOpening = true;
sendToPC("HublotOpening");
}
else if (input == 2 && !closeSwitchReached) { //close
brakeMotor(); // stop motor
delay(100);
setMotorDirection(ClosingDirection);
setMotorSpeed(255); // set motor max speed
motorRunning = true;
motorOpening = false;
sendToPC("HublotClosing");
}
else if (input == -2) { //get status
if (openSwitchReached)
sendToPC("HublotOpened");
else if (closeSwitchReached)
sendToPC("HublotClosed");
else if (motorRunning && motorOpening)
sendToPC("HublotOpening");
else if (motorRunning && !motorOpening)
sendToPC("HublotClosing");
else if (!motorRunning)
sendToPC("HublotNotMoving");
}
else if (input == -3) //Ping
sendToPC("ArduinoHublot");
else if (input == 0) { //Stop
brakeMotor(); // set motor max speed
motorRunning = false;
}
else {
sendToPC("WTF");
Serial.print(input);
}
}
void loop() {
openSwitchReached = (digitalRead(openSwitch) == HIGH);
closeSwitchReached = (digitalRead(closeSwitch) == HIGH);
if (openSwitchReached && motorRunning && motorOpening) {
sendToPC("HublotOpened");
brakeMotor();
motorRunning = false;
delay(200);
}
else if (closeSwitchReached && motorRunning && !motorOpening) {
sendToPC("HublotClosed");
brakeMotor();
motorRunning = false;
}
if (Serial.available()) {
int read = (Serial.readStringUntil(':')).toInt();
handleSerialInput(read);
}
}