I have to make a bot which has front wheel steering by one servo motor like real cars..and one driving motor to run the robot..by rotating the servo the bot will turn right and left..there are Two SONAR in left and right side to detect the distance from left and right wall..By taking the distance from both side of wall the robot has to be moved continuously forward at middle position by steering the front wheel with help of the Servo.
How can I rotate the servo with PID for smooth turning. At 118degree the servo is straight and the robot is completely forward. that means at 118degree of servo the robot will be completely straight.
How can I code the PID algorithm tor rotate the servo by taking the distance from two SONAR.
Learn how PID works if you have not already done so.
It seems to me that you are trying to minimise the difference in the distance measurement between the two sesnors, so this is probably the variable you want to control using PID.
FInd a PID library you want to use and try to work out the Kp, Ki and Kd that you need, code and then fine tune to give the result you want.
Have you thought about how you will cope with the bad readings you will occasionally get from the sensors? Or how you will phase these sensors, as you cannot run them at the same time?
I have to make a robot which has front wheel steering by one servo motor as like an RC car model. It has 2 SOnar sensors on the left and right side. Taking the distance from two side walls the robot has to be driven always in middle by steering the servo. can anyone please help me with the Arduino code or idea or anything else?
You will not find a complete code that will perform your task thoroughly. You have to write your code by yourself. However, there are many tutorials from which you can understand the idea. For example, here is one:
It shows how to connect two or more Sonar sensor to a single Arduino UNO and how to take the readings. I think, if you understand this, rest of your task will get much easier.
The servo angle is set by your code.
For typical RC car, if the steering servo in in neutral, the car will steer straight ahead. Depending on the library you are using, a command to your steering servo of say 90deg may be neutral (pulse output of 1.5 ms).
Broadly speaking, you would need to set up how and what you are trying to achieve:
do I want the car to be mid-way between each sensor?
If so, read the value of the distance from the right wall and the left side wall.
If left-distance is < right-distance, steer car towards right.
You could also search the form for RC car steering examples.
What do you mean by "the left and right side"? As in, both facing directly forward or as in one is offset from the other by a set number of degrees? How many degrees if so?
Is the goal to drive straight forward and if something is in range of one or the other or both sensors, to steer away from it until that barrier/object is no longer detected and then drive straight again?
What about stopping? Is that your "both sensors detect an object at at less than distance X therefore stop"?
These are some situations you may need to account for. For each of these situations you might have a function in your code like
yes but how can i do smooth turnings by taking the input from SONAR sensor? if I avoid if/else..what will be the other way?
You could map and constrain the sensor readings to servo.writeMicroseconds() but first you'd have to calibrate your particular servo using servo.readMicroseconds() to the neutral position, and both endpoints.
Also, take a look at this great project (not mine) and see if it gives you some ideas. It will require you installing Processing 3 but I highly recommend you playing around on Processing 3 (or 4, it's been updated since this project post!) if you're a learner and haven't before. https://create.arduino.cc/projecthub/Yug_Ajmera/radar-sonar-using-processing-3-7302c6
Hope this helps.
I had fun with an ultrasound project that used 8 Sonar devices I have modified it to use 3 sensors Echo pins attached to Digital Input pins 3, 4, and 5. all the trigger pins should be attached together and connected to pin 2.
The code uses interrupts so it is lightweight and won't interfere with your servos. since the echo pins generate the precise pulse representing the travel time of the sound wave and the trigger pin only starts the echo event you can cause all the ultrasound sensors to send out a pulse at the same time the closest objects to each will be detected.
#define TriggerPin 2 // output pin all trigger pins are linked to.
#define SamplesToAverage 5 // number of ping samples to average together for use
#define DisplayTimeDelay 60 // wait this long before sending serial output
#define DelayBetweenPings 5 // delay after ping data is completely recieved all have reported in and the nest trigger pulse in miliseconds (5 seems to be great)
unsigned long Timer, zTimer, xTimer, PingInterval, DisplayTimer; // Delay timers
volatile int PinArray[20]; // List of pins that could be used as ping inputs:
unsigned long PingTime[20] ; // interval [1000;2000] Channels 9,10,11,A0,A1
volatile int ToCompleteCtr; // when interoupted before math we need to c
volatile unsigned long PingTimeX[20]; // interval [0;65535] Channels 9,10,11,A0,A1
volatile unsigned long edgeTime[20]; // time when the pin changed states to high start of timing
volatile uint8_t PCintLast[3]; // the last state that the input pins were in
volatile uint8_t mask[3]; //looking fo pin changes using bianary
int PinMask[3]; // used to make sure all pings are recieved before sending another pulse.
int c, Pin;
int x = 0;
float inches, cm;
int feet;
int DiscardedSampleCtr;
// port change Interrupt
ISR(PCINT0_vect) { //this ISR is common to every receiver channel, it is call everytime a change state occurs on a pins 8~13
static uint8_t pin;
static unsigned long cTime;
cTime = micros(); // micros() return a uint32_t
pin = PINB; // get the state of all pins bit 0 = pin 8, bit 1 = pin 9 dtc.
ToCompleteCtr++;
sei(); // re enable other interrupts at this point, the rest of this interrupt is not so time critical and can be interrupted safely
CheckTimers(8, 13, 1, pin, cTime);
}
ISR(PCINT1_vect) { //this ISR is common to every receiver channel, it is call everytime a change state occurs on a pins A0~A5
static uint8_t pin;
static unsigned long cTime;
cTime = micros(); // micros() return a uint32_t
pin = PINC; // get the state of all pins bit 0 = pin 8, bit 1 = pin 9 dtc.
ToCompleteCtr++;
sei(); // re enable other interrupts at this point, the rest of this interrupt is not so time critical and can be interrupted safely
CheckTimers(14, 19, 2, pin, cTime);
}
ISR(PCINT2_vect) { //this ISR is common to every receiver channel, it is call everytime a change state occurs on a pins 0-7
static uint8_t pin;
static unsigned long cTime;
cTime = micros(); // micros() return a uint32_t
pin = PIND; // get the state of all pins bit 0 = pin 8, bit 1 = pin 9 dtc.
ToCompleteCtr++;
sei(); // re enable other interrupts at this point, the rest of this interrupt is not so time critical and can be interrupted safely
CheckTimers(0, 7, 0, pin, cTime);
}
void CheckTimers(uint8_t StartPin, uint8_t EndPin, uint8_t group, uint8_t pin, unsigned long cTime )
{
volatile uint16_t dTime;
mask[group] = pin ^ PCintLast[group]; // doing a ^ between the current interruption and the last one indicates wich pin changed Serial.print(mask,BIN);
PCintLast[group] = pin; // we memorize the current state of all PINs [D8-D13]
for (uint8_t ii = 0; ii <= (EndPin - StartPin); ii++) {
if (mask[group] >> ii & 1) { // pin has changed
if ((pin >> ii & 1))edgeTime[(ii + StartPin)] = cTime; //Pulse went HIGH store the start time
else { // Pulse Went low calculate the duratoin
dTime = cTime - edgeTime[(ii + StartPin)]; // Calculate the change in time
PingTimeX[(ii + StartPin)] = PingTimeX[(ii + StartPin)] + dTime; // Lets Store any duration up to 65535 micro seconds
}
}
}
ToCompleteCtr--; //when all interupts are complete this will return to zero
}
// Install Pin change interrupt for a pin, can be called multiple times
void pciSetup(byte pin)
{
if (pin <= 7)PinMask[0] = bitWrite(PinMask[0], pin, 1); // PIND for pins 0~7
else if (pin > 13) PinMask[2] = bitWrite(PinMask[2] , pin - 14, 1); // PINC for A0~A5 Starts on Pin 14
else PinMask[1] = bitWrite(PinMask[1] , pin - 8, 1); // PINB for pins 8~13
pinMode(pin, INPUT);// enable interrupt for pin...
*digitalPinToPCMSK(pin) |= bit (digitalPinToPCMSKbit(pin)); // enable pin
PCIFR |= bit (digitalPinToPCICRbit(pin)); // clear any outstanding interrupt
PCICR |= bit (digitalPinToPCICRbit(pin)); // enable interrupt for the group
PinArray[pin] = 1;
}
void setup() {
Serial.begin(115200);
Serial.println("Hello");
int i;
pinMode(2, OUTPUT);
// enable interrupt for pin...
//Select the pins you want to use for input
//pciSetup(0); //Caution this pin is Used for Serial Communication
//pciSetup(1); //Caution this pin is Used for Serial Communication
//pciSetup(2); //This is my trigger pin
pciSetup(3);
pciSetup(4);
pciSetup(5);
//pciSetup(6);
//pciSetup(7);
//pciSetup(8);
//pciSetup(9);
//pciSetup(10);
// pciSetup(11);
// pciSetup(12);
// pciSetup(13);
// pciSetup(14); // A0
// pciSetup(15); // A1
// pciSetup(16); // A2
// pciSetup(17); // A3
// pciSetup(18); // A4 // note: this is used for i2c communications
// pciSetup(19); // A5 // note: this is used for i2c communications
DisplayTimer = millis();
}
void loop() {
Timer = millis(); // required for all general timing events!
PingIt(); // Manage ping data
if (DisplayTimer <= Timer ) {
DisplayTimer = Timer + DisplayTimeDelay;
Serial.print("Sampletime:");
Serial.print(PingInterval);
Serial.print("ms\tDiscardedSamples:");// Should be 0 or greator higher than 2 means you can display faster a negitive value means it is a duplicate of last reading
Serial.print(DiscardedSampleCtr - 1);
Serial.print("\t ");
for (int i = 3; i <= 5; i++) {
inches = microsecondsToInches(PingTime[i] );
// cm = microsecondsToCentimeters(PingTime[i]);
feet = (int)floor(inches / 12);
inches = inches - (feet * 12);
Serial.print(i);
Serial.print(" = ");
Serial.print(feet);
Serial.print("' ");
Serial.print(inches, 0);
Serial.print("\", ");
// Serial.print(cm,1);
// Serial.print("cm");
Serial.print("\t ");
}
Serial.println("\t");
DiscardedSampleCtr = 0;
}
}
void PingTrigger(int Pin) {
digitalWrite(Pin, LOW);
delayMicroseconds(1);
digitalWrite(Pin, HIGH); // Trigger another pulse
delayMicroseconds(5);
digitalWrite(Pin, LOW);
}
bool AllClear() {
return (!(PinMask[0] & PIND) && !(PinMask[1] & PINB) && !(PinMask[2] & PINC) && !ToCompleteCtr); // uses "Port Registers" to quickly check the states of all the input pins we are using to make sure they are LOW
}
void PingIt() {
if ( AllClear()) { // Wait till we have all the data in before calculating distances
if (x == 0) {
xTimer = Timer + DelayBetweenPings; // Set a delay time before we send another ping and go on
x = 1; // Prevent us from changeing this time until after we sent another ping
}
if (xTimer <= Timer ) { // wait till time chatches up to xTime before sending another pulse
if (c >= SamplesToAverage) {
for (int i = 0; i <= 20; i++) if (PinArray[i]) {
PingTime[i] = (unsigned long) (PingTimeX[i] / c); // average out C samples to get more stable input
PingTimeX[i] = 0;
}
c = 0;
DiscardedSampleCtr++;
}
x = 0;
c++;
PingInterval = max((Timer - zTimer), PingInterval) ;
PingInterval = min((Timer - zTimer), PingInterval) ;
PingTrigger(TriggerPin); // Send another ping returns 0 when complete
zTimer = Timer;
}
}
}
float microsecondsToInches(long microseconds)
{
// 73.746 microseconds per inch (i.e. sound travels at 1130 feet per
// second). This gives the distance travelled by the ping, outbound
// and return, so we divide by 2 to get the distance of the obstacle.
// See: http://www.parallax.com/dl/docs/prod/acc/28015-PING-v1.3.pdf
return (float) microseconds / 74 / 2;
}
float microsecondsToCentimeters(long microseconds)
{
// The speed of sound is 340 m/s or 29 microseconds per centimeter.
// The ping travels out and back, so to find the distance of the
// object we take half of the distance travelled.
return (float)microseconds / 29 / 2;
}
Cross-posting is against the Arduino forum rules. The reason is that duplicate posts can waste the time of the people trying to help. Someone might spend a lot of time investigating and writing a detailed answer on one topic, without knowing that someone else already did the same in the other topic.
Repeated cross-posting can result in a suspension from the forum.
In the future, please only create one topic for each distinct subject matter. This is basic forum etiquette, as explained in the "How to get the best out of this forum" guide. It contains a lot of other useful information. Please read it.
That does look like fun, but the obvious question is how often reflected TX pulses from one sonar module cause false distance reports by other sonar modules.
Related to Post 14
Surprisingly little as they are all triggered at the same time. the echo pins rise at the same time and only fall when the closest object reflects back. the object needs to be in line with the sensor to be detected. so there are a lot of holes.
The Code I posted could handle up to:
16 sonar units on a single Arduino UNO. Thus leaving pins 0, 1 for serial communication to another device with the data.
// enable interrupt for pin...
//Select the pins you want to use for input
//pciSetup(0); //Caution this pin is Used for Serial Communication
//pciSetup(1); //Caution this pin is Used for Serial Communication
//pciSetup(2); //This is my trigger pin
pciSetup(3);
pciSetup(4);
pciSetup(5);
pciSetup(6);
pciSetup(7);
pciSetup(8);
pciSetup(9);
pciSetup(10);
pciSetup(11);
pciSetup(12);
pciSetup(13);
pciSetup(14); // A0
pciSetup(15); // A1
pciSetup(16); // A2
pciSetup(17); // A3
pciSetup(18); // A4 // note: this is used for i2c communications
pciSetup(19); // A5 // note: this is used for i2c communications
These are all interrupt triggered pins so other code could be running and the values would be gathered as needed.
This is my creation and I've done a lot with this base code sense
for example: Arduino_Interrupts is a library that includes several types of timers all set to connect to any pin of the arduino
As you can see the interrupts can easily be used for all these items. My Interrupts sketch allows any pin to be used as interrupts. including the ultrasound sensor
Here's an example sketch that has interrupts set for an RC Remote control 2 push buttons an ultrasound ping sensor and 1 encoder set at 4 steps per pulse cycle
This is the same thing as the attachInterrupt() function but with all pins on the Arduino UNO (atmega328p)
#include "Interrupts.h"
InterruptsClass Interrupt;
volatile long EncoderCounter = -2;
float microsecondsToInches(long microseconds)
{
// According to Parallax's datasheet for the PING))), there are
// 73.746 microseconds per inch (i.e. sound travels at 1130 feet per
// second). This gives the distance travelled by the ping, outbound
// and return, so we divide by 2 to get the distance of the obstacle.
// See: http://www.parallax.com/dl/docs/prod/acc/28015-PING-v1.3.pdf
return (float) microseconds / 74 / 2;
}
float microsecondsToCentimeters(long microseconds)
{
// The speed of sound is 340 m/s or 29 microseconds per centimeter.
// The ping travels out and back, so to find the distance of the
// object we take half of the distance travelled.
return (float)microseconds / 29 / 2;
}
void setup() {
Serial.begin(115200); //115200
Serial.println(" testing");
// put your setup code here, to run once:
pinMode(9, OUTPUT);
Interrupt.onInterrupt([](uint32_t Time, uint32_t PinsChanged, uint32_t Pins) {
sei(); // re enable other interrupts at this point,
Interrupt.PinCallBack(Time, PinsChanged, Pins);
});
Interrupt.onPin(4, INPUT_PULLUP, [](uint32_t Time, uint32_t PinsChanged, uint32_t Pins) {
if (Interrupt.CheckPin(4)) { // rising
Serial.println(" Pin 4 Rising \t");
} else { // Falling
Serial.println(" Pin 4 Falling \t");
}
});
Interrupt.onPin(5, INPUT, [](uint32_t Time, uint32_t PinsChanged, uint32_t Pins) {
uint16_t RCTime = Interrupt.RCRemote(5, Time, Pins, true);
if (RCTime) {
Serial.print(" RC Time:");
Serial.print(RCTime);
}
});
Interrupt.onPin(6, INPUT, [](uint32_t Time, uint32_t PinsChanged, uint32_t Pins) {
unsigned int PingTime = Interrupt.Ping(6, Time, Pins);
if (PingTime) {
Serial.print("Ping \t");
Serial.print(microsecondsToCentimeters(PingTime));
Serial.println("cm");
}
});
Interrupt.onPin(9, INPUT_PULLUP, [](uint32_t Time, uint32_t PinsChanged, uint32_t Pins) {
Serial.print("Switch \t");
Serial.println(Interrupt.Switch(9, Time, 1000, false));
});
Interrupt.onPin(10, INPUT_PULLUP, [](uint32_t Time, uint32_t PinsChanged, uint32_t Pins) {
Serial.print("Switch \t");
Serial.println(Interrupt.Switch(10, Time, 1000, false));
});
Interrupt.onPin(11, INPUT_PULLUP, [](uint32_t Time, uint32_t PinsChanged, uint32_t Pins) {
Serial.print("Switch \t");
Serial.println(Interrupt.Switch(11, Time, 1000, false));
});
Interrupt.onPin(12, INPUT, [](uint32_t Time, uint32_t PinsChanged, uint32_t Pins) {
EncoderCounter += Interrupt.Encoder(12, 13, Pins, true);
Serial.print("Count ");
Serial.print(EncoderCounter);
Serial.print("\t Encoder \t");
Serial.println(Interrupt.Encoder(12, 13, Pins, true));
});
Interrupt.onPin(13, INPUT, [](uint32_t Time, uint32_t PinsChanged, uint32_t Pins) {
EncoderCounter -= Interrupt.Encoder(12, 13, Pins, true);
Serial.print("Count ");
Serial.print(EncoderCounter);
Serial.print("\t Encoder \t");
Serial.println(-1 * Interrupt.Encoder(12, 13, Pins, true));
});
}
void loop() {
// put your main code here, to run repeatedly:
int t = 100;
static unsigned long _ETimer;
if ( millis() - _ETimer >= (t)) {
_ETimer += (t);
Serial.print(".");
digitalWrite(9, LOW);
delayMicroseconds(1);
digitalWrite(9, HIGH); // Trigger another pulse
delayMicroseconds(10);
digitalWrite(9, LOW);
}
}
So as you are reading along you all of a sudden find this:
What is this??? It is what is called a Lambda function, an anonymous function, or basically a function without a name.
This could have been written as :
void MyFinction (uint32_t Time, uint32_t PinsChanged, uint32_t Pins) {
EncoderCounter += Interrupt.Encoder(12, 13, Pins, true);
Serial.print("Count ");
Serial.print(EncoderCounter);
Serial.print("\t Encoder \t");
Serial.println(Interrupt.Encoder(12, 13, Pins, true));
}
// with this in the startup() function
Interrupt.onPin(12, INPUT,MyFinction );
but I decided to use lambda functions in the startup for my test example.
The "onPin" function handles setting up the correct interrupt on that pin as well as handling the callback function.
If you are looking for more I could help you with the interrupt class I created.
Z