I am trying to control the speed of a Brushless DC Motor based on the distance measured from an Ultrasonic Sensor. The ultrasonic sensor is reading distance without any issues, and the motor did spin using a potentiometer. The idea is to have the motor speed up and slow down automatically, but motor is not spinning or responding to this code. Any help is appreciated, thanks!
#include <Servo.h>
//initialization
Servo ESC_1
int Trig_Pin = 7;
int Echo_Pin = 11;
void setup() {
//set up pins
pinMode(Trig_Pin, OUTPUT);
pinMode(Echo_Pin, INPUT);
ESC_1.attach(9);
Serial.begin (9600);
}
void loop() {
if(GetDistance() >= 5 && GetDistance() <= 20){
// if distance is between 5 and 20, keep speed constant
Set_Speed(0);
delay(1000);
}
if(GetDistance() < 5){
// if distance is less than 5, slow down
Speed_Down();
}
if(GetDistance() > 20){
// if distance is greater than 20, speed up
Speed_Up();
}
// else keep speed constant
Set_Speed(0);
delay(1000);
//print the distance
Serial.print(GetDistance());
Serial.print("cm ");
Serial.println();
delay(250);
}
float GetDistance(){
// read sensor
float Duration, Sensor_Distance;
digitalWrite(Trig_Pin, LOW);
delayMicroseconds(5);
digitalWrite(Trig_Pin, HIGH);
delayMicroseconds(10);
digitalWrite(Trig_Pin, LOW);
pinMode(Echo_Pin, INPUT);
Duration = pulseIn(Echo_Pin, HIGH);
Sensor_Distance = (Duration/2) / 29.1;
return Sensor_Distance;
}
void Set_Speed(int Speed){
int Angle = map(Speed, 0, 100, 0, 180); //scale the speed to use with the motor
ESC_1.write(Angle); //send signal to ESC
}
void Speed_Up(){
//increase speed
for(int S; S <= 70; S+=5){
Set_Speed(S); //send new speed value (increasing)
delay(1000);
}
}
void Speed_Down(){
//slow down
for(int S = 70; S > 0; S -= 5){
Set_Speed(S); //send new speed value (decreasing)
delay(1000);
}
}
You mentioned that you have 2 sketches - one that reads the sensor and one that uses a pot to adjust the motor speed. Can you post those sketches?
I will find it easier to help you if I see what worked before tackling what is not working now.
I do want to make 2 notes about your current code.
Only read the sensor once at the top of the loop. Something like this snippet:
void loop() {
float DistanceReading;
DistanceReading = GetDistance();
if (DistanceReading >= 5 && DistanceReading <= 20) {
// if distance is between 5 and 20, keep speed constant
Set_Speed(0);
delay(1000);
}
if (DistanceReading < 5) {
// if distance is less than 5, slow down
Speed_Down();
}
Edit: I guess I should provide some reasoning for this. Only reading the sensor value at the top of the loop provides at least 2 advantages. First, it is quicker to read it once per loop. Second, it is safer. With your previous code, you could get a different value each time you read the sensor. So in a single loop, your tests might match on multiple different values. Best to read the value, then use that single reading for all the tests in the loop.
Delays make your program unresponsive. You are likely spending lots of time in your speed_up and speed_down routines.
Oh, hey, your speed_up does not initialize S in the loop. I wonder what that does to execution?
From what I can see SetSpeed(0) does not keep the speed constant. It sets Angle to 0 or minimum. So either the code or the comments are wrong. To keep the speed constant you just need not write anything new to the ESC.
And since you change speed in blocking for loops you basically only ever run at two speeds write(0) and write(70). You ramp up and down but you can never stop at any intermediate speed. Is that what you intend?
So in that last program why don't you just feed Sensor_ Distance (from the sensor) into the map() command instead of Val (from the pot). You'll need to adjust the map() to suit the range of values from Sensor_Distance.
Won't that do what you want, change speed with distance?