-
-
Save ShawnHymel/ccc28335978d5d5b2ce70a2a9f6935f4 to your computer and use it in GitHub Desktop.
/** | |
* Two Channel Receiver | |
* Author: Shawn Hymel (SparkFun Electronics) | |
* Date: Aug 24, 2017 | |
* | |
* Connect a TB6612FNG and RC (PWM) receiver to the Arduino. | |
* Mixes two channels for arcade drive. | |
* | |
* This code is beerware; if you see me (or any other SparkFun | |
* employee) at the local, and you've found our code helpful, | |
* please buy us a round! | |
* Distributed as-is; no warranty is given. | |
*/ | |
// Controller pins | |
const int CH_1_PIN = 10; | |
const int CH_2_PIN = 11; | |
// Motor driver pins | |
const int STBY_PIN = 9; | |
const int AIN1_PIN = 2; | |
const int AIN2_PIN = 4; | |
const int APWM_PIN = 5; | |
const int BIN1_PIN = 7; | |
const int BIN2_PIN = 8; | |
const int BPWM_PIN = 6; | |
// Parameters | |
const int deadzone = 20; // Anything between -20 and 20 is stop | |
void setup() { | |
// Configure pins | |
pinMode(STBY_PIN, OUTPUT); | |
pinMode(AIN1_PIN, OUTPUT); | |
pinMode(AIN2_PIN, OUTPUT); | |
pinMode(APWM_PIN, OUTPUT); | |
pinMode(BIN1_PIN, OUTPUT); | |
pinMode(BIN2_PIN, OUTPUT); | |
pinMode(BPWM_PIN, OUTPUT); | |
// Enable motor driver | |
digitalWrite(STBY_PIN, HIGH); | |
} | |
void loop() { | |
// Read pulse width from receiver | |
int y = pulseIn(CH_2_PIN, HIGH, 25000); | |
int x = pulseIn(CH_1_PIN, HIGH, 25000); | |
// Convert to PWM value (-255 to 255) | |
y = pulseToPWM(y); | |
x = pulseToPWM(x); | |
// Mix for arcade drive | |
int left = y + x; | |
int right = y - x; | |
// Drive motor | |
drive(left, right); | |
delay(5); | |
} | |
// Positive for forward, negative for reverse | |
void drive(int speed_a, int speed_b) { | |
// Limit speed between -255 and 255 | |
speed_a = constrain(speed_a, -255, 255); | |
speed_b = constrain(speed_b, -255, 255); | |
// Set direction for motor A | |
if ( speed_a == 0 ) { | |
digitalWrite(AIN1_PIN, LOW); | |
digitalWrite(AIN2_PIN, LOW); | |
} else if ( speed_a > 0 ) { | |
digitalWrite(AIN1_PIN, HIGH); | |
digitalWrite(AIN2_PIN, LOW); | |
} else { | |
digitalWrite(AIN1_PIN, LOW); | |
digitalWrite(AIN2_PIN, HIGH); | |
} | |
// Set direction for motor B | |
if ( speed_b == 0 ) { | |
digitalWrite(BIN1_PIN, LOW); | |
digitalWrite(BIN2_PIN, LOW); | |
} else if ( speed_b > 0 ) { | |
digitalWrite(BIN1_PIN, HIGH); | |
digitalWrite(BIN2_PIN, LOW); | |
} else { | |
digitalWrite(BIN1_PIN, LOW); | |
digitalWrite(BIN2_PIN, HIGH); | |
} | |
// Set speed | |
analogWrite(APWM_PIN, abs(speed_a)); | |
analogWrite(BPWM_PIN, abs(speed_b)); | |
} | |
// Convert RC pulse value to motor PWM value | |
int pulseToPWM(int pulse) { | |
// If we're receiving numbers, convert them to motor PWM | |
if ( pulse > 1000 ) { | |
pulse = map(pulse, 1000, 2000, -500, 500); | |
pulse = constrain(pulse, -255, 255); | |
} else { | |
pulse = 0; | |
} | |
// Anything in deadzone should stop the motor | |
if ( abs(pulse) <= deadzone ) { | |
pulse = 0; | |
} | |
return pulse; | |
} |
@Luke8826 Unfortunately, I'm not familiar with any of those components that you have shown, so I don't think I'll be able to help much. I think your best bet is to try 1 channel at a time to see how it behaves. If you have an oscilloscope, it can help you see what the output of each channel looks like.
My guess (looking at the receiver) is that your receiver is a PPM output whereas my code works with PWM output (which is different). You would need to rewrite the code to work with PPM output, as the pulse timing is very different.
I was having the same problem with the Arduino only reading One receiver channel. The other channel always returned 0. After a lot of struggling I found that if I changed the pulseIn commands delay values the Arduino started reading both channels.
The original Commands look like this
int x = pulseIn(CH_1_PIN, HIGH, 25000); l changed the value from 25000 to 30000 in both lines of code and the Arduino could then read both channels. You may have to try different values depending on which Arduino board you are using. I am using the Mega 2560...
I occasionally stumbled across this gist. For those who still struggle with Arduino, please take a look at the following project:
https://github.com/neoxic/ATmega-RC-PWM-Mixer
It's a robust interrupt-driven bidirectional 2-channel PWM motor controller firmware that can be used either with standard RC signals or iBUS (FlySky).
For those in favour of STM8 instead, take a look at a similar project:
https://github.com/neoxic/STM8-RC-PWM-Mixer
Best wishes to everybody.
I eventually end up using Digital pin 9 and 10 for the RC inputs and its working fine now. Though they all belong to PortB, this problem seems to be strange. PWM signal is present on pin 11 (confirmed by hooking up a digital Servo). I went through the datasheet of atmega328p but didn't find any clue. It's something related to timers and the library. Will dig more into the PulseIn function. I will update if I find something interesting. Thank you for the response.
hi @Vishal
I eventually end up using Digital pin 9 and 10 for the RC inputs and its working fine now. Though they all belong to PortB, this problem seems to be strange. PWM signal is present on pin 11 (confirmed by hooking up a digital Servo). I went through the datasheet of atmega328p but didn't find any clue. It's something related to timers and the library. Will dig more into the PulseIn function. I will update if I find something interesting. Thank you for the response.
can u send code of yours?
For anyone having an issue with only one channel working I have a solution. Add a delay(5); between reading the first and second channel. I think I have a delay(5); after the two pulsein() and the drive() and its working pretty sweet.
pls send the code for arduino uno also
Shawn/anyone: Why the map from -500 to 500? Why not map -255-255? It seems that you'd only get half the range of the joystick in response. Half of the PWM input range would always map above 255 and get truncated by constrain. Grateful to understand what I'm misunderstanding here.
re:
pulse = map(pulse, 1000, 2000, -500, 500);
pulse = constrain(pulse, -255, 255);
Please help, I got this code to turn on 1 motor when I push the controller forward but it will turn on the 2nd in reverse and at full speed it will jolt every 500ms intervals
left and right do nothing
Thankyou in advance