The Project: I have an HC12 transmit device running on a Nano. Attached is a joystick. The HC12 is at default settings of 9600 baud, chan 1, and FU3. The receiver is attached to a ProMicro controlling 2 gear motors. Power is 7.4 LiIon battery for the motors, 5 volts for the HC12. Most of the program was captured from How To Mechatronics and I built up from that.
The Operation: Moving the joystick left or right turns the bot left or right. Pushing up on the stick makes it go forward and pulling down makes it go in reverse. When (spring-loaded) stick is at center the bot should stop.
The Issues: I have two. 1)When I push the stick UP to go forward, it does this but it latches. When stick returns to center, the motors continue to more forward. This does NOT happen with any other movement, eg going in reverse works as expected. 2).With everything sitting still at idle, with values of X and Y streaming and printing on the robot (receiver) monitor, the static value of the Y axis suddenly goes to -1 (or -4, see program). When this happens, the motors start by themselves. Here is a screen print:
Here is the sketch of the receiver:Use code tags to format code for the forum
</*/* Name: RemoteControlBotV1.1 was previously named DejanMouseFEV24.ino
By: Bob Found, Indian Harbour, NS Canada
Start Date: 28Apr2023
Last Rev: 12Jul2023
MCU: Arduino ProMicro 3.3 volt 8 Mhz
Hardware: 2 motors, HC12 module, battery, MCU, motor driver L9110 module
Description: convert microsoft mouse into a a mouse robot by stuffing all that hardware
into a gutted mouse shell. Use PWM and remote control joystick to operate.
Vers History: V1.0 Start using Dejan Nedelkovski code
1.5 Using L9110 motor driver without enables as Dejan had, modified defines and variables
2.0 Changed processor from Nano to ProMini, 3.3 V 8Mhz 328 processor, 17500 battery
2.1 Got all logic to driver module and motors consistent with code
2.2 Put a deadband around joystick center. Motors now stop when stick is idle
2.3 Removed deadband and just made values start from center to deadband, to simplify program
2.4 Removed software serial and changed MCU to Pro Micro instead of ProMini. Using Serial1
which does not impact USB serial to monitor.
Using two gear motors instead of high speed toy car motors.
1.0 Changed name
1.1 Changes to make motors stop when stick at center
Arduino Robot Car Wireless Control using the HC-12 long range wireless module
by Dejan Nedelkovski, www.HowToMechatronics.com
*/
#define LeftMotor 5 // pin 5 Left Motor A1A //recommended is 1A=speed (PWM)
#define LeftDir 3 // pin 3 A1B // 1B=direction
#define RightMotor 9 // pin 9 Right motor B1A //recommended is 1A=speed (PWM)
#define RightDir 6 // pin 6 B1B // 1B=direction
#define DIR_DELAY 250 // brief delay for abrupt motor changes
int xAxis, yAxis;
int x = 0;
int y = 0;
int LeftSpeed = 0;
int RightSpeed = 0;
int minSpeed = 100; //min PWM value that moves motors
int maxSpeed = 255; //max PWM value max is 255
int deadband = 20; //deadband for around center stick
int XCenter = 512; //these are idle values for Nunchuk stick 516 512 for Joy on Nano
int YCenter = 496; // 528 for Nunchuk 496 for joy on Nano
int Xlo = XCenter - deadband; //20 is deadband, amount off center
int Xhi = XCenter + deadband;
int Ylo = YCenter - deadband; //i.e. 528-30=498
int Yhi = YCenter + deadband;
const int LED = 10; //LED for front of Microsoft mouse
int ledState = LOW; // initial state
unsigned long previousMillis = 0; // store last time LED was updated
const long interval = 0; // blink rate in milliseconds
//************************** Setup ********************************************
void setup() {
pinMode(LeftMotor, OUTPUT);
pinMode(LeftDir, OUTPUT);
pinMode(RightMotor, OUTPUT);
pinMode(RightDir, OUTPUT);
pinMode(LED, OUTPUT); //blink while idle with power on
Serial1.begin(9600);
Serial.begin(9600);
// Serial.println(" This is RemoteControlBotV1.1 on Pro Micro"); //program name, tests print to monitor ability
// delay(1000);
}
//*************************** Loop ********************************************
void loop() {
// Read the incoming data from the HC12
while (Serial1.available() == 0) {} //waits here forever until there is data in the buffer
delay(100); //need this
x = Serial1.read(); //gets here if there is data waiting
y = Serial1.read();
delay(10);
// Convert the 0 - maxSpeed range back to 0 - 1023
xAxis = x * 4;
yAxis = y * 4;
Serial.print("xAxis= ");
Serial.print(xAxis);
Serial.print("\t yAxis= ");
Serial.println(yAxis); //will only print if the HC12 comm is working
// LED will NOT blink if no HC12 data, blinks if data coming in, and prints statement above
//if (yAxis ==-4); {yAxis=YCenter;}
// Y-axis for Forward and Reverse
//****************Reverse****************** Stick down=1023
if (yAxis > Yhi) {
// Set Motor A backward
digitalWrite(LeftMotor, HIGH);
digitalWrite(LeftDir, LOW);
// Set Motor B backward
digitalWrite(RightMotor, HIGH);
digitalWrite(RightDir, LOW);
// Convert the declining Y-axis readings for going backward
LeftSpeed = map(yAxis, Yhi, 1023, 0, maxSpeed); //stick is 548 to 1023 going backward
RightSpeed = map(yAxis, Yhi, 1023, 0, maxSpeed);
}
//******************Forward********************* Stick up=0 LATCHES
else if (yAxis < Ylo) {
// Wait();
//delay( DIR_DELAY );
// Set Motor A forward
digitalWrite(LeftMotor, HIGH);
digitalWrite(LeftDir, HIGH);
// Set Motor B forward
digitalWrite(RightMotor, HIGH);
digitalWrite(RightDir, HIGH);
// Convert the increasing Y-axis readings for going forward
LeftSpeed = map(yAxis, 0, Ylo, 0, maxSpeed); //stick is Ylo to zero going FORWARD
RightSpeed = map(yAxis, 0, Ylo, 0, maxSpeed);
//if (yAxis ==-4); {yAxis=YCenter;}//prevents bad data (-4) from starting motor
//if joystick stays in middle the motors should not turn
} else {
LeftSpeed = 0;
RightSpeed = 0;
}
// if (yAxis ==-4); {yAxis=YCenter;}//prevents bad data (-4) from starting motor
//if (yAxis<548 && yAxis >508 && xAxis<536 && xAxis >196) {LeftSpeed=0; RightSpeed=0;}
// X-axis used for left and right control
//*******************turn LEFT******************* X left=1023
// Wait();
// delay( DIR_DELAY );
if (xAxis > Xhi) {
// Convert the increasing X-axis readings from XCenter to 1023 into increasing 0 to maxSpeed value
int xMapped = map(xAxis, Xhi, 1023, 0, maxSpeed); //Stick goes from 536 to 1023 when moving LEFT
// Move to left - decrease left motor speed, increase right motor speed
LeftSpeed = LeftSpeed - xMapped;
RightSpeed = RightSpeed + xMapped;
// Confine the range from 0 to maxSpeed
if (LeftSpeed < 0) { LeftSpeed = 0; }
if (RightSpeed > maxSpeed) {
RightSpeed = maxSpeed;
}
else {
LeftSpeed = 0;
RightSpeed = 0;
}
}
//*******************turn Right******************** x right=0
// Wait();
// delay( DIR_DELAY );
if (xAxis < Xlo) {
// Convert the decreasing X-axis readings from XCenter to 0 into 0 to maxSpeed value
int xMapped = map(xAxis, Xlo, 0, 0, maxSpeed); //Stick goes from 196 to 0 when moving RIGHT
// Move right - decrease right motor speed, increase left motor speed
LeftSpeed = LeftSpeed + xMapped;
RightSpeed = RightSpeed - xMapped;
// Confine the range from 0 to maxSpeed
if (LeftSpeed > maxSpeed) { LeftSpeed = maxSpeed; }
if (RightSpeed < 0) { RightSpeed = 0; }
}
// Prevent buzzing at low speeds
if (LeftSpeed < minSpeed) { LeftSpeed = 0; }
if (RightSpeed < minSpeed) { RightSpeed = 0; }
analogWrite(LeftMotor, LeftSpeed); // Send PWM signal to motor A
analogWrite(RightMotor, RightSpeed); // Send PWM signal to motor B
//****************************************************
/* unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {//note where loop bracket is at very end.
previousMillis = currentMillis;
// if the LED is off turn it on and vice-versa:
if (ledState == LOW) {ledState = HIGH;}
else {ledState = LOW;}
digitalWrite(LED, ledState);
}//end millis
*/
//******************************************************
} //end loop
void Wait() {
digitalWrite(LeftDir, LOW);
digitalWrite(LeftMotor, LOW);
digitalWrite(RightDir, LOW);
digitalWrite(RightMotor, LOW);
}>
**What I've Tried:** I tried changing timing around the reading of the HC12 received bytes. I've added delays (10-20 mS) around the commands. I tried using a conditional "if Y==-1, make Y=YCenter" or similar. I've tried to see if the "miss" was from the transmitter or receiver and it seems somewhere in between, ie the transmission itself. I put a capacitor across HC12 power to try to keep voltage steady when transmitting. Matters not if power is coming from battery or if it's coming from USB for the receiver. The transmitter is powered by USB but I have option for 12 volts to the Nano. The two devices are 12 inches apart. (Maybe too close?). I have an LCD readout on the Tx that is steady when the joystick is not moved. I've changed out HC12, in fact changed the entire transmitter- either transmitter results in -1 appearing in Receiver, so it's unlikely the source of the problem. HOWEVER, if I leave the transmitter powered off...the bot motors do not start up. This makes sense since the line while (Serial1.available() == 0) {} prevents any code from running until there is something in the receive buffer.
**What to do Next:** Well I don't know and that's why I'm here. Should I play with baud rate (up or down)? Or change channel to another, thinking there is interference with other devices on this frequency? Note that the motors don't run if my transmitter is off so there is no interference from something else.
`