Der Code erlaubt die Bluetooth Fernsteuerung von zweimotorigen Fahrzeugen am Beispiel eines Raddampfers, dessen beide Wasserräder zum Antrieb und zur Lenkung dienen.
Autor: Christian
/* BEERLECADA paddle steamer * Product: P211106_paddle_steamer Authors: Christian Rempel Laurin Kettner Licence: Beer(red wine) licence Connections: Arduino Module D3 left PWM speed (BEERLECADA Motordriver) D5 left direction LOW = FORWARD (BEERLECADA Motordriver) D6 right PWM speed (BEERLECADA Motordriver) D7 BT RXD PIN (HC05) D8 BT TXN PIN (HC05) D9 right direction LOW = FORWARD (BEERLECADA Motordriver) We are working with the free controller app for android Arduino Joystick available in Google playstore from uncia robotics. It has a joystick and 4 buttons, but for this paddle weel ship we are only using the joystick after all */ #include <SoftwareSerial.h> // more than often two servos from the same manufatucer are working with different movement velocitys // given the same volt. So here we are defining what bounderies it takes for them to spin in the same speed. #define leftSpeedLow 56 #define leftSpeedHigh 100 #define rightSpeedLow 126 #define rightSpeedHigh 200 // defines if the arduino is trying to send Debug values to the serial interface #define isDebugPrinting false SoftwareSerial BTSerial(7, 8); // CONNECT BT RXD PIN TO ARDUINO 8 PIN | CONNECT BT TXN PIN TO ARDUINO 7 PIN // after this amount of time without user input the servos auomaicly stop // this is a nessesary secuite mesure to stop the ship if the bluetooth connection was lost long joysticktimer; long printTimer; // timer to print int leftspeed = 0; // speed of left servo; goes from leftSpeedLow up to leftSpeedHigh int rightspeed = 0; // speed of right servo; goes from rightSpeedLow up to rightSpeedHigh int angle = 0; // angle of joystick, cached for median int strength = 0; // strength of joystick, cached for median void setup() { pinMode(3, OUTPUT);// left speed pinMode(5, OUTPUT);// left direction LOW = FORWARD pinMode(6, OUTPUT);// right speed pinMode(9, OUTPUT);// right direction LOW = FORWARD //stop everything and set direction to foreward digitalWrite(3, LOW); digitalWrite(5, LOW); digitalWrite(6, LOW); digitalWrite(9, LOW); Serial.begin(9600);// serial interface BTSerial.begin(9600); // HC-05 default speed in AT command more joysticktimer = millis(); if (isDebugPrinting) printTimer = millis(); delay(200); } void loop() { if (BTSerial.available() > 0) { joysticktimer = millis(); // reset timer, we got a new value String val = BTSerial.readStringUntil('#'); // the app starts every new package with a "#" if ((val.length() == 7) && (isValidNumber(val))) { // check if the message recived was valid // reads angle and strength and smooths tem since the values highly fluctuate angle = (int)(angle * 0.9 + val.substring(0, 3).toInt() * 0.1); strength = (int)(strength * 0.9 + val.substring(3, 6).toInt() * 0.1); handlejoystick(); //translate the angle and strength values to servo values } // the app is likely to send faster than we are working, trash all the // old recived packages and start with a fresh one next loop Serial.flush(); } if ((millis() - joysticktimer) > 300) { // stops the servos if no user input was given in a short amount of time angle = 0; strength = 0; handlejoystick(); } if (isDebugPrinting && ((millis() - printTimer) > 1000)) { Serial.println("Speed left: " + (String)leftspeed + "; right: " + (String)rightspeed); } } // translate the angle and strength values to motor values // this is not a trivial task since we have only 2 spinning weels to steer void handlejoystick(void) { // if it should stop just skip all the calculating and stop imidiently if (strength <= 0) { //with the app we are using strength goes from 0 to 100, 0 means the joystick is in resting position leftspeed = 0; rightspeed = 0; analogWrite(3, 0); analogWrite(6, 0); return; } // pin 3 and 5 are the left motor, where 3 is the velocity and 5 the direction // pin 6 and 9 are the right motor, where 6 is the velocity and 9 the direction // tracks if we are in the upper / lower half of the joystick witch translates to foreward / backward bool lower; float cosinus; lower = (angle >= 180);//determing the lower half = backwards; angle goes from 0° (leftsense) allaround to 360° // start with right half of the joy stick pad if (angle <= 90 || angle >= 270) { leftspeed = strength; cosinus = cos(2 * angle * PI / 180); // if cosinus greater than zero, the right motor turns backwards // i. e. smaller then 45° or greater then 315° rightspeed = (int)(strength * (-cosinus)); } else {// left half rightspeed = strength; cosinus = cos(2 * angle * PI / 180); // if the cosinus is greater then zero, the left motor turns backwards // i. e. smaller greater then 135° and then 225° leftspeed = (int)(strength * (-cosinus)); } if (lower) { // moving backwards leftspeed = -leftspeed; rightspeed = -rightspeed; } // writing direction if (leftspeed < 0) digitalWrite(5, HIGH); else digitalWrite(5, LOW); if (rightspeed < 0) digitalWrite(9, HIGH); else digitalWrite(9, LOW); /* long map(long x, long in_min, long in_max, long out_min, long out_max) { return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; } */ leftspeed = sign(leftspeed) * map(abs(leftspeed) * 10, 0, 1000, leftSpeedLow, leftSpeedHigh); rightspeed = sign (rightspeed) * map(abs(rightspeed) * 10, 0, 1000, rightSpeedLow, rightSpeedHigh); //writing velocity, while the global variable tracks the direction, only positiv volt values are possible analogWrite(3, abs(leftspeed)); analogWrite(6, abs(rightspeed)); } //returns signum of int num int sign(int num) { if (signbit(num)) return -1; else return 1; } //returns only true if every char in String is a digit boolean isValidNumber(String str) { for (char c : str) { if (!isDigit(c)) return false; } return true; }