Hi everyone,
So far, any problem I have had I have found answers by searching the forums or with Google. But not so this time.
Arduino Uno (R3), with TowerPro MG996R
My problem is that I am driving a servo using ServoTimer2. It works for a few seconds, then stops. I use the Serial Monitor to see the value I am passing to ServoTimer2 continues to change (and it does), but the pulse width out of the servo pin stops changing. Like I said, it works for a few seconds, the pulse width varies with the value passed to the ServoTimer2 library function, but then stops varying even though the value passed to it continues to vary. I can see on my scope the pulse width is around the 1.0 - 1.5ms, and the pulses come one for each 12-13ms. All that sounds ok from what I have read
It’s a remote control car and the servo does the steering.
I am using ServoTimer2 because I am using VirtualWire (which had timer conflicts with the ‘Servo’ library).
I have had this arrangement work before and I didn’t see this behaviour. I had other problems then. What I have changed since then is I got rid of a stepper motor I was using to drive the back wheels and replaced it with a DC motor (still to be tested), which means I removed the call to the ‘stepper’ library functions and now will just use analogWrite. Also, I have added some simple code to turn headlights on and off, and tidied up the code a bit.
But I don’t think I have broken anything because IT WORKS! (for a while)… so maybe something is a little bit broken.
I will attach my code. It looks more complex than it is (I will remove some superfluous commentary).
The transmitter sends the A/D values from the joysticks, and sticks an A or B at the front to differentiate which data is for steering and for speed (it also sends a C or D to turn lights on and off).
This code receives the transmitted data and decodes it. This has worked in my earlier version when other things weren’t working very well.
The received data is turned back into a number from a string, then mapped to a useful scale.
If anyone else has seen this behaviour from ServoTimer2, I would love to hear about it.
Thanks,
Eric
#include <ServoTimer2.h> // Doesnt' seem to let me use pin 11 for analogWrite!
#include <VirtualWire.h> // Takes over control of pins 9, 10, so can't use them
// also takes over timer1, that's why use ServoTimer2.
#define MIN_PULSE 750 // Min and max times permissible for ServoTimer2.
#define MAX_PULSE 2250 // These values are pulse durations in microseconds.
// need to undef the following for Virtual Wire?
#undef int
#undef abs
#undef double
#undef float
#undef round
int MotorSpeed; // Speed setting
int SpeedReading; // Signal received from transmitter after conversion from string
char SpeedString[4]; // String recieved from transmitter, after removal of leading character
int SteerPosn;
int SteerReading; // ditto for steering
char SteerString[4];
char LightString[1]; // record light input light command so can be displayed
int LIGHTS = 3; // drive headlights from pin 1
int IN1 = 7; // IN1 and IN2 control motor direction
int IN2 = 8;
int ENA = 5; // must be PWM, duty cycle determines DC motor speed
int LED = 13; // There is a LED on the Arduino board connected at pin 13.
ServoTimer2 servoSteer; // create servo object to control the steering servo motor
//------------
void setup() {
pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
pinMode(ENA, OUTPUT);
digitalWrite(IN1, LOW);
digitalWrite(IN2, LOW);
analogWrite(ENA, 0); // should be able to use both digitalWrite and analogWrite on one pin.
pinMode(LED, OUTPUT);
digitalWrite(LED, LOW); // debug, to see what MotorDriver is doing
pinMode(LIGHTS, OUTPUT);
digitalWrite(LIGHTS, LOW);
servoSteer.attach(6); // attaches the servo on pin 6 (a PWM pin) to the servo object
Serial.begin(9600); // start serial comms to the monitor for debugging
// setup VirtualWire for RF comms
vw_set_ptt_inverted(true); // Required for my transmitter/receiver (I think)
vw_set_rx_pin(2); // receive data on this pin
vw_setup(2000); // Bits per sec
vw_rx_start(); // Start the receiver PLL running
LightString[0] = 'C'; // Initialise lights to be off
}
//-----------
void loop() {
// First, decode transmitted data
uint8_t buf[VW_MAX_MESSAGE_LEN]; // these lines copied from VirtualWire
uint8_t buflen = VW_MAX_MESSAGE_LEN; // example code.
if (vw_get_message(buf, &buflen)) // Non-blocking... whatever that means
{
int i;
if(buf[0] == 'A') // data is Speed data
{
for (i=0; i<(buflen-1); i++)
SpeedString[i] = char(buf[i+1]); // copy data, leaving out leading 'A' or 'B' char
SpeedString[(buflen-1)] = '\0';
}
else if(buf[0] == 'B') // data is Steering data
{
for (i=0; i<(buflen-1); i++)
SteerString[i] = char(buf[i+1]);
SteerString[(buflen-1)] = '\0';
}
else if(buf[0] == 'C') // turn lights on
{
digitalWrite(LIGHTS, HIGH);
LightString[0] = 'C';
}
else if(buf[0] == 'D') // turn lights off
{
digitalWrite(LIGHTS, LOW);
LightString[0] = 'D';
}
else
Serial.println(" uh oh "); // debug
}
// Second, manipulate speed and steering data to useable formats
SpeedReading = atoi(SpeedString);
MotorSpeed = map(SpeedReading, 0, 1023, -255, 255); // convert 10-bit A/D to 8-bit PWM (+ and - range)
SteerReading = atoi(SteerString);
SteerPosn = map(SteerReading, 0, 1023, MAX_PULSE, MIN_PULSE);
// Now set speed
if (MotorSpeed > 30)
{
// set motor direction
digitalWrite(IN2, LOW);
digitalWrite(IN1, HIGH);
// set motor speed
analogWrite(ENA, MotorSpeed);
}
else if (MotorSpeed < -30)
{
// reverse motor direction
digitalWrite(IN1, LOW);
digitalWrite(IN2, HIGH);
// set motor speed
analogWrite(ENA, -MotorSpeed); // Value must be positive, 0-255
}
else
digitalWrite(ENA, LOW); // Disable the driver, turn the motor off, should be able to
// use analogWrite and digitalWrite on the same pin for UNO
// Now set steering
servoSteer.write(SteerPosn);
// Send data to serial monitor for debugging:
Serial.print(", MotorSpeed = ");
Serial.print(MotorSpeed);
Serial.print(", SteerPosn = ");
Serial.println(SteerPosn);
}