Library for Pololu m3pi line-following robot. Implements the serial slave commands. for MBED OS V6

m3pi.cpp

Committer:
eencae
Date:
2017-04-04
Revision:
0:56320ef879a6
Child:
1:5523d6d1feec

File content as of revision 0:56320ef879a6:

#include "m3pi.h"

////////////////////////// constructor/destructor //////////////////////////////


m3pi::m3pi()
{
    _serial = new Serial(p9,p10);
    _reset = new DigitalOut(p23);
    _button = new DigitalIn(p21);
    _leds = new BusOut(p20,p19,p18,p17,p16,p15,p14,p13);
}

m3pi::~m3pi()
{
    delete _serial;
    delete _reset;
    delete _button;
    delete _leds;
}

/////////////////////////////// public methods /////////////////////////////////

void m3pi::write_leds(int val)
{
    // check within limits
    val = val > 255 ? 255 : val;
    val = val < 0 ? 0 : val;

    _leds->write(val);
}

void m3pi::init()
{
    _serial->baud(115200);
    reset();                        // hard rest of 3pi
    stop();                         // stop motors
    lcd_clear();                    // clear LCD
    write_leds(0);                  // turn off LEDs
    _button->mode(PullUp);           // turn pull-up on
}

void m3pi::get_signature(char *signature)
{
    _serial->putc(0x81);
    _serial->gets(signature,7);
}

void m3pi::get_raw_values(unsigned int *values)
{
    _serial->putc(0x86);

    for (int i=0; i<5; i++) {
        char lsb = _serial->getc();
        char msb = _serial->getc();
        unsigned int value = (msb<<8 | lsb);
        values[i]=value;
    }
}

void m3pi::get_calibrated_values(unsigned int *values)
{
    _serial->putc(0x87);

    for (int i=0; i<5; i++) {
        char lsb = _serial->getc();
        char msb = _serial->getc();
        unsigned int value = (msb<<8 | lsb);
        values[i]=value;
    }

}

float m3pi::get_trimpot_value()
{
    _serial->putc(0xB0);
    char lsb = _serial->getc();
    char msb = _serial->getc();
    // trimpot value in the range 0 - 1023
    float value = ( msb<<8 | lsb ) / 1023.0;
    return value;
}


float m3pi::get_battery_voltage()
{
    _serial->putc(0xB1);
    char lsb = _serial->getc();
    char msb = _serial->getc();
    // Battery in mV so convert to volts
    float voltage = ( msb<<8 | lsb ) / 1000.0;
    return voltage;
}

void m3pi::play_music(const char notes[],int length)
{
    length = length < 0 ? 0 : length;
    length = length > 100 ? 100 : length;

    _serial->putc(0xB3);
    _serial->putc(length);

    for (int i = 0 ; i < length ; i++) {
        _serial->putc(notes[i]);
    }
}


void m3pi::calibrate()
{
    reset_calibration();

    lcd_goto_xy(0,0);
    lcd_print("Place on",8);
    lcd_goto_xy(0,1);
    lcd_print("  line  ",8);

    wait(1.0);

    lcd_clear();
    lcd_goto_xy(0,0);
    lcd_print(" Press  ",8);
    lcd_goto_xy(0,1);
    lcd_print("to begin",8);

    while( read_button() ) {
        // loop while waiting for button to be press
    }

    wait(1.0);

    lcd_clear();
    lcd_goto_xy(0,0);
    lcd_print("Reading ",8);
    lcd_goto_xy(0,1);
    lcd_print("Sensors ",8);

    spin_right(0.1);

    char led_val = 0;
    Timer timer;
    timer.start();

    while (timer.read() < 10.0) {
        write_leds(led_val++);

        if (led_val > 255) {
            led_val = 0;
        }

        _serial->putc(0xB4);
        wait_ms(5);
    }

    timer.stop();

    write_leds(255);
    stop();

    lcd_clear();
    lcd_goto_xy(0,0);
    lcd_print("Place on",8);
    lcd_goto_xy(0,1);
    lcd_print("  line  ",8);

    while( read_button() ) {
        // loop while waiting for button to be press
    }

    lcd_clear();
    write_leds(0);
    wait(1.0);
}

void m3pi::reset_calibration()
{
    _serial->putc(0xB5);
    wait_ms(50);
}

int m3pi::get_line_position()
{
    _serial->putc(0xB6);

    // order is different from claimed in User Guide?
    char lsb = _serial->getc();
    char msb = _serial->getc();
    int position = (msb<<8 | lsb);

    return position - 2000;
}

float m3pi::get_normalised_line_position()
{
    int position = get_line_position();
    return float(position)/2000.0;
}

void m3pi::lcd_clear()
{
    _serial->putc(0xB7);
}

void m3pi::lcd_print(char text[],int length)
{
    length = length < 0 ? 0 : length;
    length = length > 8 ? 8 : length;

    _serial->putc(0xB8);
    _serial->putc(length);

    for (int i = 0 ; i < length ; i++) {
        _serial->putc(text[i]);
    }
}

void m3pi::lcd_goto_xy(int x, int y)
{
    _serial->putc(0xB9);
    _serial->putc(x);
    _serial->putc(y);

}

void m3pi::auto_calibrate()
{
    reset_calibration();            // clear previous calibration

    _serial->putc(0xBA);
    write_leds(0xFF);  // LEDs on
    while(1) {
        if (_serial->readable()) {
            break;
        }
    }
    write_leds(0);    // LEDs off
}

void m3pi::left_motor(float speed)
{
    // check within bounds
    speed = speed > 1.0 ? 1.0 : speed;
    speed = speed < -1.0 ? -1.0 : speed;

    if (speed > 0.0) {  // forward
        _serial->putc(0xC1);
        char s = char(127.0*speed);
        _serial->putc(s);
    } else { // backward - speed is negative
        _serial->putc(0xC2);
        char s = char(-127.0*speed);
        _serial->putc(s);
    }

}

void m3pi::right_motor(float speed)
{
    // check within bounds
    speed = speed > 1.0 ? 1.0 : speed;
    speed = speed < -1.0 ? -1.0 : speed;

    if (speed > 0.0) {  // forward
        _serial->putc(0xC5);
        char s = char(127.0*speed);
        _serial->putc(s);
    } else { // backward - speed is negative
        _serial->putc(0xC6);
        char s = char(-127.0*speed);
        _serial->putc(s);
    }

}

// speeds from -1.0 to 1.0 (0 is stop)
void m3pi::motors(float left_speed,float right_speed)
{
    left_motor(left_speed);
    right_motor(right_speed);
}


void m3pi::stop()
{
    left_motor(0.0);
    right_motor(0.0);
}

// speed in range 0.0 to 1.0
void m3pi::forward(float speed)
{
    speed = speed > 1.0 ? 1.0 : speed;
    speed = speed < 0.0 ? 0.0 : speed;

    left_motor(speed);
    right_motor(speed);
}

// speed in range 0 to 1.0
void m3pi::reverse(float speed)
{
    speed = speed > 1.0 ? 1.0 : speed;
    speed = speed < 0.0 ? 0.0 : speed;

    left_motor(-speed);
    right_motor(-speed);
}

void m3pi::spin_right(float speed)
{

    speed = speed > 1.0 ? 1.0 : speed;
    speed = speed < 0.0 ? 0.0 : speed;

    left_motor(speed);
    right_motor(-speed);
}

void m3pi::spin_left(float speed)
{

    speed = speed > 1.0 ? 1.0 : speed;
    speed = speed < 0.0 ? 0.0 : speed;

    left_motor(-speed);
    right_motor(speed);
}

int m3pi::read_button()
{
    return _button->read();
}

void m3pi::display_battery_voltage(int x,int y)
{
    float voltage = get_battery_voltage();

    char buffer[8];
    sprintf(buffer,"%3.1f V",voltage);

    lcd_goto_xy(x,y);
    lcd_print(buffer,5);
}

void m3pi::display_signature(int x,int y)
{
    _serial->putc(0x81);
    char buffer[7];  // including NULL terminator
    _serial->gets(buffer,7);

    lcd_goto_xy(x,y);
    lcd_print(buffer,6);
}

/////////////////////////////// private methods ////////////////////////////////

void m3pi::reset()
{
    // pulse the reset line (active-high)
    _reset->write(0);
    wait_ms(100);
    _reset->write(1);
    wait_ms(100);
}