Code for automatic pill box dispenser

Dependencies:   mbed-rtos mbed sMotor

main.cpp

Committer:
cchoi63
Date:
2017-12-13
Revision:
1:71eb56bcafce
Parent:
0:d223f8829ec0

File content as of revision 1:71eb56bcafce:

/*
----- Authors -----

Sahithi Bonala
Stephen Brotman
Christie Choi
Brandon Sheu

----- Acknowledgements -----

Samuel Matildes (sam.naeec@gmail.com) for the sMotor v0.1 Test Program that
interfaces between the mbed and 4-phase stepper motors.

*/
 
#include "mbed.h"
#include "sMotor.h"
#include "rtos.h"

//Interrupts
InterruptIn touchsensor(p12); // Touch sensor

//Digital Inputs
DigitalIn refill_pb(p30); // Pushbutton to refill

//Digital Outputs
DigitalOut myled(LED1);
DigitalOut myled2(LED2);

//PWM Outputs
PwmOut led_red(p21); // Red LED of an RGB LED
PwmOut led_green(p22); // Green LED of an RGB LED
PwmOut led_blue(p23); // Blue LED of an RGB LED

//Serial Connection
Serial pc(USBTX, USBRX);

//sMotor Interface
sMotor motor(p8, p9, p10, p11); // Creates new stepper motor: IN1, IN2, IN3, IN4

//Threads
Thread thread_motor; // Motor thread
Thread thread_refill; // Refill thread
Thread thread_control; // Timing controller thread
Thread thread_led; // LED thread
Thread thread_cmd; // Serial command thread

//Timing
Timer timer;
Ticker ticker;

//Initialization for LED
float led_red_value = 0.0; //current red LED value
float led_green_value = 0.0; //current green LED value
float led_blue_value = 0.0; //current blue LED value
int led_color = 0x000000; //color of the LED
int led_gradient_duration = 3; //duration of gradient between LED colors
bool led_blink = false; //whether to blink the LED
bool led_update = false; //whether to update the color of the LED

//Initialization for stepper motor
int step_speed = 1200; //set default motor speed
int numstep = 512 ; //defines full turn of 360 degree
bool motor_turn = false; //whether to turn the motor or not

//Initialization for the pill container
float pill_interval = 15.0; //time between pills (seconds)
int pill_taken_counter = 0;
int pill_refill_counter = 0;
bool pill_taken = false;
bool pill_refilled = false;

bool cmd_send = false;
int cmd_type = 0; //1 is time, 2 is pill

void SendCmdTime() {
    //Send a command through Serial telling the mySQL database to update the
    //time 
    cmd_type = 1;
    cmd_send = true;
}

void SendCmdPill() {
    // Send a command through Serial telling the mySQL database to update the
    // pill status
    cmd_type = 2;
    cmd_send = true;
}

void ControlCmd() {
    while (true) {
        if (cmd_send) {
            switch (cmd_type) {
                case 1:
                    pc.printf("cmdTime\n");
                    break;
                case 2:
                    pc.printf("cmdPill\n");
                    break;
            }
            cmd_type = 0;
            cmd_send = false;
        }
        Thread::wait(200);
    }
}

void TouchDetected() {
    // Called when the touch sensor detects a touch
    pill_taken = true;
    myled2 = true;
    
    // Update the status in the database
    SendCmdPill();
}

void TouchRemoved() {
    // Called to reset variables when the touch sensor no longer detects a touch
    pill_taken = false;
    myled2 = false;
}

void UpdateLed(int color, bool blink = false, int duration = 3) {
    // Update the color of the LED
    led_color = color;
    led_blink = blink;
    led_gradient_duration = duration;
    led_update = true;
}

void ControlLed() {
    //thread for RGB LED that uses global variables
    //(int) led_color - a hexadecimal value for the color, e.g. 0xFF0000 for red
    //(int) led_blink (optional) - whether to blink or not
    //(int) led_gradient_duration (optional) - duration for gradient in seconds

    while (true) {
        if (led_update) {
            float r = ((float)((0xFF0000 & led_color)>>16))/255.0;
            float g = ((float)((0x00FF00 & led_color)>>8))/255.0;
            float b = ((float)(0x0000FF & led_color))/255.0;
            //pc.printf("R: %0.2f, G: %0.2f, B: %0.2f\n", r, g, b);
            float dR = (r-led_red_value)/(100.0);
            float dG = (g-led_green_value)/(100.0);
            float dB = (b-led_blue_value)/(100.0);
            for (int i = 1; i <= 100; i++) {
                led_red.write(led_red_value + (dR*i));
                led_green.write(led_green_value + (dG*i));
                led_blue.write(led_blue_value + (dB*i));
                wait(((float)led_gradient_duration)/(100.0));
            }
            
            if (led_blink) {
                float time_wait = (float)led_gradient_duration*0.125;
                for (int i = 0; i < 4; i++) {
                    // Turn off LED
                    led_red.write(0.0);
                    led_green.write(0.0);
                    led_blue.write(0.0);
                    wait(time_wait);
                    
                    // Turn on LED
                    led_red.write(r);
                    led_green.write(g);
                    led_blue.write(b);
                    wait(time_wait);
                }
            }
            
            led_red_value = r;
            led_green_value = g;
            led_blue_value = b;
            
            led_update = false;
        }
        Thread::wait(500);
    }
}

void ControlTiming() {
    timer.start();
    ticker.attach(&SendCmdTime, pill_interval);

    while(true) {
        int delay = (pill_taken_counter+1)*pill_interval;
        float time_difference = timer.read()-delay;
        float time_limit_warn = pill_interval/5.0;
        float time_limit_alert = pill_interval/4.0;
        
        if (pill_taken) {
            // Pill is taken
            UpdateLed(0x000000, false);
            
            if (timer.read() >= delay) {
                // Increment container
                motor_turn = true;
            } else {
                motor_turn = false;
            }
        } else if (time_difference >= -pill_interval &&
                time_difference < time_limit_warn) {
            // Pill is ready to be taken
            UpdateLed(0x00FF00, false);
        } else if (time_difference >= time_limit_warn &&
                time_difference < time_limit_alert) {
            // Pill still not taken, warning
            // change LED color
            UpdateLed(0xFFFF00, true);
        } else if (time_difference >= time_limit_alert) {
            // Pill still not taken, alert
            UpdateLed(0xFF0000, true);
        } else {
            UpdateLed(0x000000, false);
        }
        
        if (pill_taken_counter == 7) {
            UpdateLed(0x0000FF, false);
        }
        
        if (pill_refilled) {
            ticker.detach();
            timer.stop();
            timer.reset();
            timer.start();
            ticker.attach(&SendCmdTime, pill_interval);

            pill_refilled = false;
            
            UpdateLed(0x000000, false);
        }
        
        Thread::wait(100);
    }
}

void ControlMotor() {
     while(true) {
         while (pill_taken_counter < 7) {
             if (motor_turn == true) {
                motor.step(numstep/7, 0, step_speed); // Number of steps, direction, speed
                pill_taken_counter++;
                
                // Reest touch sensor variables
                TouchRemoved();
                motor_turn = false;
             }
        }
        Thread::wait(500);
    }
}

void ControlRefill() {
    //refill_pb.mode(PullUp); 
    while(true) {
        while (pill_taken_counter == 7) {
            myled = 1;
            wait(0.2);
            myled = 0;
            wait(0.2);
            if (refill_pb == 0 && pill_refill_counter < 6) {
                pill_refill_counter++;
                motor.step(numstep/7, 0, step_speed);
            }
        
            if (pill_refill_counter == 6 && refill_pb == 0) {
                motor.step(numstep/7, 0, step_speed);
                pill_taken_counter = 0;
                pill_refill_counter = 0;
                pill_refilled = true;
            }
        }
        Thread::wait(500);
    }
}
 
int main() {
    //Set refill pushbutton as a pull-up
    refill_pb.mode(PullUp);
    
    //Initiate touch sensor interrupt
    touchsensor.fall(&TouchDetected);
    
    //Start threads
    thread_motor.start(ControlMotor);
    thread_refill.start(ControlRefill);
    thread_control.start(ControlTiming);
    thread_led.start(ControlLed);
    thread_cmd.start(ControlCmd);
    
    //Write LED values
    led_red.period(0.0005); //2kHz period for less flicker
    led_green.period(0.0005); //2kHz period for less flicker
    led_blue.period(0.0005); //2kHz period for less flicker
    led_red.write(led_red_value);
    led_green.write(led_green_value);
    led_blue.write(led_blue_value);
}