hey there I'm fairly new to using arduino but comfortable with coding in general. I'm trying to control a servo motor via a bluetooth connection with my phone but I'm having some troubles. I've started off following this hackster instruction thing. I've plugged in everything the same way this guy has, used the same code and when I used the built in serial monitor the servo turned a little bit, not at all 90 degrees and then it wouldn't respond to anymore inputs. I then did a little debugging of my own by adding in a 7 segment display to figure out how much the servo turns. I also switched over to using a bluetooth app on my phone Arduino Bluetooth Control by broxcode on the Play Store. I've been using the slider function of the app while with a limit of 180 being the farthest the slider can go. This is all using this code below
// including the servo library
#include <Servo.h>
// declaring and defining myservo
Servo myservo;
// this variable holds the values that the servo will move
int Position ;
#include "Arduino.h"
#include <TM1637Display.h>
// all_on pins connected to the TM1637 display
const byte CLK_PIN = 6;
const byte DIO_PIN = 5;
// Create display object of type TM1637Display:
TM1637Display lander_display = TM1637Display(CLK_PIN, DIO_PIN);
const byte all_on[] = { 0b11111111,
0b11111111,
0b11111111,
0b11111111 };
#include <SoftwareSerial.h>
SoftwareSerial BTPart(1,0);//(10, 11); // TX, RX
//^This part is mandatory for working with phone app otherwise just serial monitor works
//Also can't be called Serial because that is already a designated variable name
void setup()
{
lander_display.setBrightness(7); // Configure the display brightness (0-7):
// myservo is connected to PWM pin 9
myservo.attach(9);
//settin up the baud rate for the bluetooth module and mobile to communicate
BTPart.begin(9600);
lander_display.setSegments(all_on);
delay(1000);
lander_display.clear(); // Clear the display (all segments off)
delay(1000); // Delay 1 seconds and then repeat our demo.
}
void loop()
{
if (BTPart.available() )
{
//if the values recieved are equal to 0 or 90 the sero will move to the respective angl
Position = BTPart.read(); //something is not quite right here check with other bluetooth 7 segment file for debugging
//if (Position == '0' || Position == '90') {
myservo.write(Position);
//BTPart.println("test");
BTPart.println("\n"+Position ); //why is it printing to the same line?
BTPart.println("\n");
delay(15);
//}
lander_display.showNumberDec(Position);
}
//lander_display.showNumberDec(Position);
}
I am quite bamboozled because for some reason the slider and the button parts of the app are quite off from the degrees the servo is turning. for example when I put the slider to 0 the display shows 48 and when I go to any number higher than 10 the display shows 255 and the servo motor just freaks out. Its also odd because when putting the slider to numbers lower than 10 the display and servo work in not properly but in an expected way ie putting the slider to 9 shows 57, 8 shows 56 etc. interestingly the serial monitor in the arduino ide show the same number as the slider. I'm really confused why this is happening as I would like the slider to be the number of degrees the servo is currently at. One other minor problem I am having is that when the serial monitor in the ide shows a number it shows it on the same line so after a while there is just looks like one really big number. Any help would be greatly appreciated.
Maybe I´ll not be able to solve all the problems, but I think I have some directions:
It makes no sense to use SoftwareSerial library at the pins 0&1, as they are actually the Hardware Serial (RX and TX) ports. They are used to communicate with the serial monitor and if you plug the HC-05/06 module to it, you won´t be able to use the serial monitor anymore.
While you have the project under development, choose another pair of pins to use within SoftwareSerial. When the project is finished, you can then connect the Bluetooth module to pins 0 and 1and get rid of the SoftwareSerial library.
57 is the ASCII code for the number 9. And 56 is the ASCII code for 8. So, the data seems to be correct, but in the wrong format. Take a look in how the phone app send the data and how this line is dealing with it:
So If I'm understanding you correctly in your first point if I use pins that aren't 0 and 1 such as 10 and 11 for example I can use both the bluetooth app and the serial monitor?
For your second point something is definitely going on because I went into the terminal section of the app and after you put in a number it spits out some weird symbols and then the number entered. I've also noticed that in other cases people will put the 'single quotation' marks around their variable for example in my case 'Position'. I tried putting quotations around the code you mentioned above but then the display only puts out a really big number. I don't quite understood this as the variable is always defined as an int. And to me it seems it would be asked for as a string
Precisely. In this case pins 10&11 would be responsible for receiving and sending the signals to the bluetooth module. While 0&1 would allow you to see what´s happening through the Serial Monitor.
By the way, you didn´t mention your setup. Is it an Uno R3 with HC-06/HC-05?
There is a difference in using Strings and C strings (zero terminated character arrays). When you use single quotations marks, you´re using the second, but in your sketch the variable position is an int (as you defined it) and you might let it just as it is (no quotes nor single quotes).
My suggestion is for you to abandon the display for now and try to establish the comms between the app and the Uno. Change the pins of Software Serial to 10&11 and test this:
// including the servo library
#include <Servo.h>
// declaring and defining myservo
Servo myservo;
// this variable holds the values that the servo will move
int Position;
#include "Arduino.h"
#include <TM1637Display.h>
// all_on pins connected to the TM1637 display
const byte CLK_PIN = 6;
const byte DIO_PIN = 5;
// Create display object of type TM1637Display:
TM1637Display lander_display = TM1637Display(CLK_PIN, DIO_PIN);
const byte all_on[] = { 0b11111111,
0b11111111,
0b11111111,
0b11111111 };
#include <SoftwareSerial.h>
SoftwareSerial BTPart(10, 11); // TX, RX
//^This part is mandatory for working with phone app otherwise just serial monitor works
//Also can't be called Serial because that is already a designated variable name
void setup()
{
lander_display.setBrightness(7); // Configure the display brightness (0-7):
// myservo is connected to PWM pin 9
myservo.attach(9);
//settin up the baud rate for the bluetooth module and mobile to communicate
BTPart.begin(9600);
Serial.begin(9600);
lander_display.setSegments(all_on);
delay(1000);
lander_display.clear(); // Clear the display (all segments off)
delay(1000); // Delay 1 seconds and then repeat our demo.
}
void loop() {
if (BTPart.available() > 0) {
//if the values recieved are equal to 0 or 90 the sero will move to the respective angl
Position = BTPart.read();
if (Position == '0' || Position == '90') {
myservo.write(Position);
Serial.print("The received angle is:" );
Serial.println(Position)
//BTPart.println("test");
//BTPart.println("\n"+Position ); //why is it printing to the same line?
//BTPart.println("\n");
delay(15);
}
//lander_display.showNumberDec(Position);
}
//lander_display.showNumberDec(Position);
}
and see in the Serial Monitor what value is being received.
So I tested out your code verbatim and inputting 0 the recieved angle was 48 and inputting 90 the recieved angle was also 48.
Then I tested out the code commenting out the if statement if (Position == '0' || Position == '90') {
but keeping what was inside of it uncommented the same as how I did in the original code I posted and i put these numbers and got these results respectively
input--The received angle is:
1----49
8----56
9----57
10---49 and 48
15---49 and 53
90---57 and 48
100--49, 48 and 48
120-- 49, 50 and 48
180--49, 56 and 48
Just to make sure I was fully understanding the pattern of the numbers I tried putting in 42069 and The recieved angles were 52, 50, 48, 54, and 57 respectively. I also then thought maybe the delay(15) was making it think that each digit was a seperate input but removing the delay actually didn't change anything. However I did find that upping the delay to 1000 or 1 second does further prove that each digit is treated as its own input bc there is a second delay between the outputs
So I've done some further research and apparently the Software Serial uses a unit8_t variable to transmit and receive. which according to the internet guarantees an 8-bit unsigned integer and can store a value from 0-255. I've been messing around and found that you can input the entire alphabet a coming out as 97 and z being 122. Apparently A comes out as 65 and Z comes out as 90. I tried using the map function
Position = BTPart.read();
realPos = map(Position, 0,1024, 0,180);
or
Position = BTPart.read();
realPos = map(Position, 255, 0,180);
but that doesn't seem to get me anywhere. I also think I might just need to figure out the right number instead of 255 or 1024
There´s no need to use Map. Actually if you just do realPos = Position - 48 you´ll be able to solve the problem for numbers smaller than 10.
Will your servo sweep all the positions between 0 and 90 degrees or they will only get to 0 or 90?
If they will be 0 OR 90, you can bypass the problem assuming 48 for zero and 57 for 90.
Are you sure there´s no option to set the app to send the info in another format?
Since a byte can be anything from 0 to 255, it would be better if you can send a byte instead of a set of char.
Yes I have tested the servo to make sure it works properly by using the example sweep code and I will say the servo can go from 0 to about 179, it's just shy of a full 180.
If they will be 0 OR 90, you can bypass the problem assuming 48 for zero and 57 for 90.
I want to attach my servo to a key which has a couple different positions, each being 40 degrees apart. The problem is I don't quite trust my engineering skills to be able to rig up a 3d printed attachment to be 100% precise so I want to be able to make little increments on the servo to be able to adjust for the play in the system.
Are you sure there´s no option to set the app to send the info in another format?
Since a byte can be anything from 0 to 255, it would be better if you can send a byte instead of a set of char.
I've downloaded a couple of apps but I think they all just send a char variable
There´s no need to use Map. Actually if you just do realPos = Position - 48 you´ll be able to solve the problem for numbers smaller than 10.
This is pretty smart I'll try this and see how it goes
Here is an extremely terrible circuit diagram that I drew up in tinkercad. everything is powered via the arduino 5v. Tinkercad doesn't have the HC-05/6 module so I don't have it shown. I don't currently have my arduino but I have a breadboard which has the 5v and ground connected. The motor, display, and bluetooth module ground and VCC are attached to the breadboard. Very importantly at the beginning of this project I had the TX and RX ends of the HC-05 connected to pins 1 and 0 respectively. But now they are connected to 10 and 11. Also I'm not quite using a standard arduino r3 I'm using a hero Arduino board which for all intensive purposes functions as an r3. Right now I am using a microservo this one to be exact. In the future I think I'll probably upgrade to a stronger servo perhaps an RC servo motor, if that happens I'll use one of those breadboard power supplies but for now the 5v of the arduino is working fine.
Ok, so let's say you have 0º, 40º, 80º, 120º, 160º and 179º. In this case you have 6 positions, that can be easily named {0,1,2,3,4,5}, or , for a direct correspondence to the info you´re receiving from the Bluetooth {48,49,50,51,52,53}. You can include in you sketch a switch-case condition that moves the servo to the nth position, whatever are the ones that fits your key.
PS: I´m obviously seeking the easiest/laziest solution to avoid implementing a more complex system to receive and parse a group of numbers in ASCII format. In any case, you might like to take a look in Serial Input Basics. It can be useful in the future.
It turns out making an app on MIT app inventor is actually not that hard, I have experience using code.org. For whatever reason the slider in the app uses a float variable, so now I no don't have to work around the goofy way the other arduino apps are sending data.
why do that when you could just send a data type that is more compatible with a servo motor lol.
Making my own app is actually way better anyway it does exactly the way I want... usually. Here is a link to app.