code to follow variable PWM signal "solved"

Hello Guys
I used a sketch posted by Panther3001 located here: Solved: reading PWM signal: the "noInterrupts()" function crashes my code! - Programming Questions - Arduino Forum
and modified it to control the Osepp motor shield using the motor shield library. The original sketch simply reads PWM output of the receiver.
I have an old 72 MHz transmitter/ receiver 4 ch setup to control a dual motor tank with tracks.
I've modified the sketch to read and control the throttle/speed of the tank and read a second channel to control direction/steering by currently stopping the left or right motor.
My question is: Ive written several versions that attempt to control left and right movement with out actually stopping the motor, just slow it down which I prefer. Can you lead me in the right direction to slow the motor smoothly. I tried to write several versions that were along the lines of:

if (duration1 >= 1550) {
motor1.setSpeed((duration1 / 4) -duration0 / 4);
}
duration0 is the throttle and duration1 is the steering
It works to slow down the motor up to a point then goes back to full speed when the stick is press all the way in one direction. I'm assuming the calculation gets to a point that is no longer valid and goes back to duration0 speed.

Any suggestions would be great!
Had to post the sketch separate because the forum said my message was to large.
please look to the next post for sketch

#include <AFMotor.h>
AF_DCMotor motor1(1);
AF_DCMotor motor2(2);

//Global Initializations
const int input_pin0 = 19;
const int input_pin1 = 18;

volatile int input_state0 = LOW; //initialize input state
volatile int input_state1 = LOW;
volatile boolean process_data0 = false; //is it time to process the data?
volatile boolean process_data1 = false;
volatile unsigned long t_start = 0; //us; the start time of a HIGH pulse
volatile unsigned long t_end = 0;
volatile unsigned long t_end_old = 0; //us; the previous t_end value (ie: from the previous iteration)
volatile unsigned long duration0 = 0; //us; the time of a high pulse
volatile unsigned long duration1 = 0;

unsigned long dt = 0; //us; the period of the entire PWM cycle (ex: for a 50Hz PWM RC communication signal, the period, or dt = 20ms = 20000us)
unsigned long counter = 0; //loop counter
float freq = 1; //Hz; the PWM frequency

//calculate length of the data arrays
int array_length0 = sizeof(duration0)/sizeof(unsigned long);
int array_length1 = sizeof(duration1)/sizeof(unsigned long);

void setup() {
pinMode(input_pin0, INPUT);
pinMode(input_pin1, INPUT);
attachInterrupt(4, interrupt_triggered0, CHANGE); //attach an interrupt to interrupt 0 (on digital pin 2)
attachInterrupt(5, interrupt_triggered1, CHANGE); //attach an interrupt to interrupt 0 (on digital pin 2)
motor1.setSpeed(0);
motor2.setSpeed(0);
motor1.run(RELEASE);
motor2.run(RELEASE);
Serial.begin(115200);
}

void loop() {

if (process_data0)
{ //get PWM period
dt = t_end - t_end_old; //us; the PWM period in microseconds
//get PWM freq
freq = 1.0/(dt*(float)1e-6); //Hz; the PWM frequency

counter++; //update the loop counter

//output the data every ___ cycles (if you set this ___ to ‘freq,’ you get an output once per second)
if (counter%((unsigned int)freq/10)==0){ //if counter modulus ___ == 0 //for a 45Hz PWM signal being read, output data at ~4 Hz.

Serial.print("duration0(us): “);
Serial.print(duration0); //the high pulse time
Serial.print(” duration1(us): ");
Serial.println(duration1); //the high pulse time
}
process_data0 = false; //reset
} //end of processing data

}

void interrupt_triggered0(){
//begin interrupt code
volatile int val = digitalRead(input_pin0);

if (val!=input_state0){ //if a change actually occured and it was NOT just noise on the pin
input_state0 = val; //update the pin input state
if (input_state0==HIGH) //if the pin is now HIGH
{
t_start = micros(); //capture the time stamp of the rising edge
}
else //if the pin is now LOW
{
t_end_old = t_end; //us; update this value just before you replace t_end with a new value
t_end = micros(); //capture the time stamp of the falling edge (remember, we already ensured that an input_state change DID occur)
duration0 = t_end - t_start; //us; the duration of the HIGH pulse
process_data0 = true; //update variable in order to process & output data
//noInterrupts(); //turn off interrupts during data processing
}}}
void interrupt_triggered1(){
volatile int val1 = digitalRead(input_pin1);

if (val1!=input_state1){ //if a change actually occured and it was NOT just noise on the pin
input_state1 = val1; //update the pin input state
if (input_state1==HIGH) //if the pin is now HIGH
{
t_start = micros(); //capture the time stamp of the rising edge
}
else //if the pin is now LOW
{
t_end_old = t_end; //us; update this value just before you replace t_end with a new value
t_end = micros(); //capture the time stamp of the falling edge (remember, we already ensured that an input_state change DID occur)
duration1 = t_end - t_start; //us; the duration of the HIGH pulse
process_data1 = true; //update variable in order to process & output data
} }
// Begin motor control with ossep shield
if (duration0 >=1175){
motor1.run (FORWARD);
motor2.run (FORWARD);
motor1.setSpeed(duration0/4);
motor2.setSpeed(duration0/4);
}
else{
motor1.run (RELEASE);
motor2.run (RELEASE);
}
if (duration1>1850){
motor2.setSpeed(RELEASE);
}
else{
motor2.setSpeed(duration0/4);
}
if (duration1<1150){
motor1.setSpeed(RELEASE);
}
else{
motor1.setSpeed(duration0/4);
}}

What you're trying to do is mix the two signals together. You can get RC modules to do that for you but it is also easy to do in software. Conceptually, it works like this:

int leftSpeed = constrain(avgSpeed + steering, -255, 255);
int rightSpeed = constrain(avgSpeed - steering, -255, 255);

The result is two values which are in the range +/- 255, where -255 represents full speed backwards, 0 represents stationary and +255 represents full speed forwards. To drive each motor from the corresponding value you would test whether the value was positive or negative, set the direction accordingly and then apply the absolute value to the pwm input of the motor driver.

Thank you for responding PeterH

This equipment I pulled out of the closet is 20+ years old, I'm lucky it still works let alone mix the signals for me. :smiley:
I do know what you mean though.
As for the code I Think I get what you mean.
This might not be what you meant at all but this is what I'm getting.
You constrain the total read value of throttle and left "same for right" from -255 to +255 and look for the LOW or HIGH to set direction.
If I do it this way won't the left or right motor not reach full value unless I throttle full and press the steering in one direction or the other?
Or am I totally missing it?
Thanks

You've got the right idea. I had assumed that your input averageSpeed and steering values were in the range +/- 255 to start with, and that +/- 255 represented full speed in either direction. Of course you could choose to represent the speed range differently if you wanted. The range +/- 255 is just convenient when your motor output consists of a PWM output since analogWrite supports a range of 0 .. 255.

With all those assumptions out of the way, with no steering input the output speeds are the same as the input speed so you have full speed forwards and reverse. Full steering with an average speed of zero gives you +255 on one output and -255 on the other so the vehicle would speed on the spot. Full speed forward with a bit of steering would give you +255 on one track and (255 - a bit) on the other; the constrain call prevents the output from going past 'full throttle' in either direction.

You might find that once you have the basic logic working you want to tailor it so the steering sensitivity is reduced as the speed goes up, and that sort of thing can be achieved very easily by a little bit of arithmetic.

Hello again PeterH

Your last comment is exactly what I'm trying to achieve.
If I press full throttle, then it should move ahead in a straight line at full speed "in a perfect world" :smiley:
What I'm trying to achieve beyond that is when steering is pressed the opposite motor from the direction I want to go slows down based on how much I press the steering stick in one direction or the other.

When I first posted I was trying a calculation that look some thing like this:
if (SteeringLeft >= 1550) {
motor1.setSpeed((SteeringLeft / 4) -Throttle / 4);
}
The Principal idea worked but the calculation must be wrong.
When I add this line to the sketch, the motor slows down to a certain point then goes back to full throttle as I continue to press the steering stick farther in that direction.
I assuming that the constraint command needs to be used prior to the lines I'm trying to write so it can only slow to 0 and not beyond.
Does that sound right or am I approaching it wrong?

Peter

I wrote what I thought we might be talking about and posted just that part below.
I always get confused on how to make a new integer read and follow the value of another.
For example below: I tried to make a new integer “Speed” and have it analog.read “duration0” then map the values and constrain them.
The results should be mapped from 1140, 1940, to 0, 255. What i actually get is -299 all the time.
It does not change when I move the speed stick. Should it be an analog.Read from Duration0?
Or something else.
Thanks

// Begin motor control with ossep shield
Speed = analogRead(duration0);
Speed = constrain(Speed, 0, 255);
Speed = map(Speed, 1140, 1940, 0, 255);
Steering = analogRead(duration1);
Steering = constrain(Steering, -255, 255);
Steering = map(Steering, 1140, 1940, -255, 255);
if (Speed >=20){
motor1.run (FORWARD);
motor2.run (FORWARD);
motor1.setSpeed(Speed);
motor2.setSpeed(Speed);
}
else{
motor1.run (RELEASE);
motor2.run (RELEASE);
}
if (Steering >= 20){
motor2.setSpeed(RELEASE);
}
else{
motor2.setSpeed(Speed);
}
if (Steering <= -20){
motor1.setSpeed(RELEASE);
}
else{
motor1.setSpeed(Speed);
}}

Something odd here:

    Speed = analogRead(duration0);
    Speed = constrain(Speed, 0, 255);
    Speed = map(Speed, 1140, 1940, 0, 255);

The first line sets speed to a value between 0 and 1023.
The second caps speed at 255.
The third maps values of speed between 1140 and 1940 to a range of 0 to 255.

Problem is, when you execute the map, speed is already in the range 0 to 255, so your expectation that it will be between 1140 and 1940 is false, hence the peculiar answer you get.

Thanks for replying WildBill

I can’t disagree that it might seem odd. :blush:
I’m still learning
So analog.read sets it between 0 and 1023, I guess I should have known that, plenty of other projects where I used that.
What I’m trying to do is Read “duration0” which is a PWM value from 1140 to 1940 read in the Serial port, rename it and map it
from 0, 255. Not sure if I need to use constrain if the numbers will only be 0, 255
The first problem I have is picking up “duration0” values and renaming them to Speed. Analog.read was my attempt to do that.
I’m pretty new to this and get confused on how to read from another integer.
any suggestions?
Thanks again

Solved
I was going about it the long way.
I read up on pulsein and wrote a small sketch based on that.
Posted below. It works fine but had a problem with mapping “Steering” to a negative number so I just used the numbers available and it works fine.
Thanks for everyone’s help.
Any suggestions to make it better are welcome.
#include <AFMotor.h>
AF_DCMotor motor1(1);
AF_DCMotor motor2(2);

const int input_pin0 = 19;
const int input_pin1 = 18;

unsigned long Speed;
unsigned long Steering;

void setup() {
pinMode(input_pin0, INPUT);
pinMode(input_pin1, INPUT);
motor1.setSpeed(0);
motor2.setSpeed(0);
motor1.run(RELEASE);
motor2.run(RELEASE);
Serial.begin(115200);
}
void loop() {

Serial.print(" Speed “);
Serial.print(Speed);
Serial.print(” Steering ");
Serial.println(Steering);

Speed = pulseIn(input_pin0, HIGH);
Steering = pulseIn(input_pin1, HIGH);
Speed = map(Speed, 1100, 1940, 0, 255);
Speed = constrain(Speed, 10, 255);
//Steering = map(Steering, 1140, 1940, 255, -255);
// Steering = constrain(Steering,255, -255);

if (Speed >=25){
motor1.run (FORWARD);
motor2.run (FORWARD);
motor1.setSpeed(Speed);
motor2.setSpeed(Speed);
}
else{
motor1.run (RELEASE);
motor2.run (RELEASE);
}
if (Steering >1550){
motor2.setSpeed(Speed - Steering/3);
}
else{
motor2.setSpeed(Speed);
}
if (Steering < 1475){
motor1.setSpeed(Speed + Steering/3);
}
else{
motor1.setSpeed(Speed);
}
}