hi I'm trying to achieve a rotational position control on my DC motor by reading the encoder and using 3 analog inputs to calculate pwm and degree of rotation. The code runs but the positioning is far from being precise. What am I doing wrong here? Would appreciate any and all feedback.
#include <TimerThree.h>
#include <TimerOne.h>
#include <Math.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
// Constants
float Max_Sweep_Angle = 30; // claw sweep angle that corrspondts to max air volume to be delivered
float Hold_time = 1000; // hold time (in ms) between inhale and exhale to maintain air pressure in lungs before exhaling
float Pinion_Gear_Teeth = 30; // number of teeth on gear directly attached to motor shaft (pinion)
float Claw_Gear_Teeth = 48; // number of teeth on gear driven by the pinion
float Max_Tidal_Volume = 800; // maximum volume of air to be delivered to patient
//Variables
float BPM = A0; // BPM potentiometer
float Tidal_Volume = A1; // Tidal_Volume potentiometer
float IE = A2; // inhale/exhale ratio
float BPM_Value = 0; // variable to store the value coming from the sensor
float Tidal_Volume_Value = 0;
float IE_Value = 0;
int Pressure_Value = 0;
int Opto_Interrupt_Value = 0;
int PWM2;
int PWM6;
// Inputs
int motor_home = 6;
int motor_inhale = 2;
int motor_dir = 4;
int opto_interrupt = 7;
int pressure_sensor = 8;
int button_1 = 50;
int button_2 = 48;
int ENCODER_A = 18; // pin 18 is an interrupt pin and is more reliable physical connection on the board
int ENCODER_B = 12;
int rpmcount = 0;
unsigned long enc_inhale_counter = 0;
unsigned long enc_exhale_counter = 0;
void setup() {
// declare potentiometers as inputs
Serial.begin(9600);
pinMode(BPM, INPUT);
pinMode(Tidal_Volume, INPUT);
pinMode(IE, INPUT);
// declare OUTPUT PINS FOR INHALE AND EXHALE PWMs:
pinMode(motor_inhale, OUTPUT);
pinMode(motor_dir, OUTPUT);
// declare buttons as input
pinMode(motor_home, INPUT);
pinMode(opto_interrupt, INPUT);
pinMode(pressure_sensor,INPUT);
pinMode(ENCODER_A, INPUT); // may need to change these to input_pulup
pinMode(ENCODER_B, INPUT);
// LCD setup
lcd.init(); // initialize the lcd
lcd.init();
// Print a message to the LCD.
lcd.backlight();
}
void loop() {
//pinMode(opto_interrupt, INPUT_PULLUP);
// read the value from the pots:
BPM_Value = analogRead(BPM);
Tidal_Volume_Value = analogRead(Tidal_Volume);
IE_Value = analogRead(IE);
Pressure_Value = digitalRead(pressure_sensor);
Opto_Interrupt_Value = digitalRead(opto_interrupt);
// map pot readings to actual values defined in the clinical specs
float Actual_BPM_Value = map(BPM_Value, 0, 1023, 6, 40); // breaths per minute 6 - 40 (breath period 60/BPM)
float Actual_Tidal_Volume_Value = map(Tidal_Volume_Value, 0, 1023, 200, 800); // Tidal volume 200 ml - 800 ml. In terms of encoder pulses: (800 ml/30 degrees)*(3.4 degrees/1 pulse) = 90.7 ml/pulse
float Actual_IE_Value = map(IE_Value, 0, 1023, 1, 4); // I/E inhale time/exhale time ratio 1/1 - 1/4 (given as 1- 4)
float Breath_period = (60UL/Actual_BPM_Value);
float t_inhale = (Breath_period)/(1+Actual_IE_Value);
float t_exhale = Breath_period - t_inhale;
float arm_speed = (radians(Max_Sweep_Angle)/t_inhale)*(Actual_Tidal_Volume_Value/Max_Tidal_Volume);
float pinion_speed = arm_speed*(Claw_Gear_Teeth/Pinion_Gear_Teeth);
float RPM = (pinion_speed*60UL)/(2*PI);
float pos_duty_cycle = (RPM/26)*100; // 340 is max NO LOAD RPM of AndyMark NeveRest planetary gear motor which is used here (assumption: 12V - 340 RPM)
float volume_pulses = Actual_Tidal_Volume_Value/91;
// Convert Actual_BPM_Value, Actual_Tidal Volume_Value, Actual_IE_Value from float to int for LCD
int LCD_BPM = int(Actual_BPM_Value);
int LCD_Tidal_Volume = int(Actual_Tidal_Volume_Value);
int LCD_IE = int(Actual_IE_Value);
// Display BPM, Tidal Volume, IE to LCD
lcd.setCursor(0,0);
lcd.print("BPM ");
lcd.print(LCD_BPM);
lcd.setCursor(7,0);
lcd.print(" Vol ");
lcd.print(LCD_Tidal_Volume);
lcd.setCursor(6,1);
lcd.print("IE ");
lcd.print(LCD_IE);
if(Pressure_Value == HIGH){
// Initiate inhale
while(int(enc_inhale_counter) <= int(volume_pulses)){
digitalWrite(motor_dir, HIGH);
analogWrite(motor_inhale, int(pos_duty_cycle));
Serial.println("duty cycle for inhale = \t");
Serial.println(pos_duty_cycle);
if(digitalRead(ENCODER_A) == HIGH){ //reading both encoder signals results in inaccurate count: && digitalRead(ENCODER_B) == LOW
enc_inhale_counter++;
}
Serial.println("Pulse count in inhale loop = \t");
Serial.println(enc_inhale_counter);
}
enc_inhale_counter = 0;
digitalWrite(motor_inhale, LOW);
digitalWrite(motor_dir, LOW);
delay(Hold_time);
while(int(enc_exhale_counter) <= int(volume_pulses)){
Serial.println("in exhale");
digitalWrite(motor_dir, LOW); // 7-30-2020 enters this loop but motor doesn't go back
analogWrite(motor_inhale, int(pos_duty_cycle)); // check in actual setup and verify if this is an appropriate duty cycle
if(digitalRead(ENCODER_A) == LOW){
enc_exhale_counter++;
}
Serial.println("Pulse count in exhale loop = \t");
Serial.println(enc_exhale_counter);
}
enc_exhale_counter = 0;
digitalWrite(motor_inhale, LOW);
digitalWrite(motor_dir, HIGH);
}
}
here's the serial readout; as you can see the counter is inconsistent
10:00:02.590 -> `f~`f⸮⸮f⸮⸮⸮fx⸮⸮⸮⸮⸮⸮⸮⸮⸮fduty cycle for inhale =
10:00:02.590 -> 24.62
10:00:02.590 -> Pulse count in inhale loop =
10:00:02.627 -> 0
10:00:02.627 -> duty cycle for inhale =
10:00:02.661 -> 24.62
10:00:02.661 -> Pulse count in inhale loop =
10:00:02.697 -> 1
10:00:02.697 -> duty cycle for inhale =
10:00:02.730 -> 24.62
10:00:02.730 -> Pulse count in inhale loop =
10:00:02.766 -> 1
10:00:02.766 -> duty cycle for inhale =
10:00:02.802 -> 24.62
10:00:02.802 -> Pulse count in inhale loop =
10:00:02.836 -> 2
10:00:02.836 -> duty cycle for inhale =
10:00:02.872 -> 24.62
10:00:02.872 -> Pulse count in inhale loop =
10:00:02.908 -> 3
10:00:02.908 -> duty cycle for inhale =
10:00:02.944 -> 24.62
10:00:02.944 -> Pulse count in inhale loop =
10:00:02.980 -> 3
10:00:02.980 -> duty cycle for inhale =
10:00:03.016 -> 24.62
10:00:03.052 -> Pulse count in inhale loop =
10:00:03.088 -> 3
10:00:03.088 -> duty cycle for inhale =
10:00:03.088 -> 24.62
10:00:03.124 -> Pulse count in inhale loop =
10:00:03.124 -> 4
10:00:03.124 -> duty cycle for inhale =
10:00:03.160 -> 24.62
10:00:03.160 -> Pulse count in inhale loop =
10:00:03.196 -> 4
10:00:03.196 -> duty cycle for inhale =
10:00:03.233 -> 24.62
10:00:03.233 -> Pulse count in inhale loop =
10:00:03.269 -> 5
10:00:04.225 -> in exhale
10:00:04.225 -> Pulse count in exhale loop =
10:00:04.261 -> 1
10:00:04.261 -> in exhale
10:00:04.261 -> Pulse count in exhale loop =
10:00:04.297 -> 2
10:00:04.297 -> in exhale
10:00:04.334 -> Pulse count in exhale loop =
10:00:04.368 -> 2
10:00:04.368 -> in exhale
10:00:04.368 -> Pulse count in exhale loop =
10:00:04.405 -> 3
10:00:04.405 -> in exhale
10:00:04.441 -> Pulse count in exhale loop =
10:00:04.477 -> 3
10:00:04.477 -> in exhale
10:00:04.477 -> Pulse count in exhale loop =
10:00:04.512 -> 4
10:00:04.512 -> in exhale
10:00:04.512 -> Pulse count in exhale loop =
10:00:04.548 -> 5