Energy harvesting mobile robot. Developed at Institute of Systems and Robotics — University of Coimbra.
Fork of ISR_Mini-explorer by
robot.h
- Committer:
- fabiofaria
- Date:
- 2017-07-27
- Revision:
- 1:d1443589406e
- Parent:
- 0:15a30802e719
File content as of revision 1:d1443589406e:
/** @file */
//AUTOR: Fernando Pais
//MAIL: ferpais2508@gmail.com
//DATA: 6/6/2016
// VERSÃO 6.4.0
//
//Alterações: Problema de compatibilidade entre encoder e infravermelho resolvido
// Odometria actualizada automaticamente
// Valor da bateria verificado na inicialização
// Motores movem-se de 0 a 1000 para melhor difrenciação
//
//#include "mbed.h"
//#include "init.h"
//#define _USE_MATH_DEFINES
# define M_PI 3.14159265358979323846 /* pi */
#include <math.h>
#include <string.h>
#include "VCNL40x0.h"
void Odometria();
// classes adicionais
VCNL40x0 VCNL40x0_Device (PTC9, PTC8, VCNL40x0_ADDRESS);
Timeout timeout;
Serial pc(PTE0,PTE1);
I2C i2c(PTC9,PTC8);
I2C i2c1(PTC11,PTC10);
// Variables needed by the lib
unsigned int ProxiValue=0;
short int prev_R=0;
short int prev_L=0;
long int total_R=0;
long int total_L=0;
long int ticks2d=0;
long int ticks2e=0;
float X=20;
float Y=20;
float AtractX = 0;
float AtractY = 0;
float theta=0;
int sensor_left=0;
int sensor_front=0;
int sensor_right=0;
short int flag=0;
int IRobot=0;
int JRobot=0;
//SAIDAS DIGITAIS (normal)
DigitalOut q_pha_mot_rig (PTE4,0); //Phase Motor Right
DigitalOut q_sleep_mot_rig (PTE3,0); //Nano Sleep Motor Right
DigitalOut q_pha_mot_lef (PTA17,0); //Phase Motor Left
DigitalOut q_sleep_mot_lef (PTB11,0); //Nano Sleep Motor Left
DigitalOut q_pow_ena_i2c_p (PTE2,0); //Power Enable i2c FET P (0- enable 1-disable)
DigitalOut q_pow_ena_mic_p (PTA14,0); //Power enable Micro FET P (0- enable 1-disable)
DigitalOut q_pow_as5600_n (PTC6,1); //AS5600 Power MOSFET N (1- enable 0-disable)
DigitalOut q_pow_as5600_p (PTC5,0); //AS5600 Power MOSFET P (0- enable 1-disable)
DigitalOut q_pow_spi (PTC4,0); //SPI Power MOSFET P (0- enable 1-disable)
DigitalOut q_ena_mppt (PTC0,0); //Enable MPPT Control (0- enable 1-disable)
DigitalOut q_boost_ps (PTC7,1); //Boost Power Save (1- enable 0-disable)
DigitalOut q_tca9548_reset (PTC3,1); //Reset TCA9548 (1- enable 0-disable)
DigitalOut power_36khz (PTD0,0); //Power enable pic12f - 36khz (0- enable 1-disable)
// ********************************************************************
// ********************************************************************
//DEFINIÇÃO DE ENTRADAS E SAIDAS DO ROBOT
//ENTRADAS DIGITAIS (normal input)
DigitalIn i_enc_dir_rig (PTB8); //Encoder Right Direction
DigitalIn i_enc_dir_lef (PTB9); //Encoder Left Direction
DigitalIn i_micro_sd_det (PTC16); //MICRO SD Card Detect
DigitalIn i_mppt_fail (PTE5); //Fail MPPT Signal
DigitalIn i_usb_volt (PTB10); //USB Voltage detect
DigitalIn i_sup_cap_est (PTB19); //Supercap State Charger
DigitalIn i_li_ion_est (PTB18); //Li-ion State Charger
// ********************************************************************
//ENTRADAS DIGITAIS (external interrupt)
InterruptIn i_int_mpu9250 (PTA15); //Interrupt MPU9250
InterruptIn i_int_isl29125 (PTA16); //Interrupt ISL29125 Color S.
InterruptIn i_mic_f_l (PTD7); //Interrupt Comp Micro F L
InterruptIn i_mic_f_r (PTD6); //Interrupt Comp Micro F R
InterruptIn i_mic_r_c (PTD5); //Interrupt Comp Micro R C
// ********************************************************************
//ENTRADAS ANALOGICAS
AnalogIn a_enc_rig (PTC2); //Encoder Left Output_AS_MR
AnalogIn a_enc_lef (PTC1); //Encoder Right Output_AS_ML
AnalogIn a_mic_f_l (PTB0); //Analog microphone F L
AnalogIn a_mic_f_r (PTB1); //Analog microphone F R
AnalogIn a_mic_r_c (PTB2); //Analog microphone R C
AnalogIn a_temp_bat (PTB3); //Temperature Battery
// ********************************************************************
//PWM OR DIGITAL OUTPUT NORMAL
//DigitalOut q_led_whi (PTE29); //Led white pwm
DigitalOut q_led_red_fro (PTA4); //Led Red Front
DigitalOut q_led_gre_fro (PTA5); //Led Green Front
DigitalOut q_led_blu_fro (PTA12); //Led Blue Front
DigitalOut q_led_red_rea (PTD4); //Led Red Rear
DigitalOut q_led_gre_rea (PTA1); //Led Green Rear
DigitalOut q_led_blu_rea (PTA2); //Led Blue Rear
//SAIDAS DIGITAIS (pwm)
PwmOut pwm_mot_rig (PTE20); //PWM Enable Motor Right
PwmOut pwm_mot_lef (PTE31); //PWM Enable Motor Left
PwmOut pwm_buzzer (PTE21); //Buzzer PWM
PwmOut pwm_led_whi (PTE29); //Led white pwm
// ********************************************************************
//SAIDAS ANALOGICAS
AnalogOut dac_comp_mic (PTE30); //Dac_Comparator MIC
/* Powers up all the VCNL4020. */
void init_Infrared()
{
VCNL40x0_Device.SetCurrent (20); // Set current to 200mA
}
/**
* Selects the wich infrared to comunicate.
*
* @param ch - Infrared to read (1..5)
*/
void tca9548_select_ch(char ch)
{
char ch_f[1];
char addr=0xE0;
if(ch==0)
ch_f[0]=1;
if(ch>=1)
ch_f[0]=1<<ch;
i2c.start();
i2c.write(addr,ch_f,1);
i2c.stop();
}
/**
* Get ADC value of the chosen infrared.
*
* @param ch - Infrared to read (1..5)
*
* Note: for the values of ch it reads (0-right, ... ,4-left, 5-back)
*/
long int read_Infrared(char ch) // 0-direita 4-esquerda 5-tras
{
tca9548_select_ch(ch);
VCNL40x0_Device.ReadProxiOnDemand (&ProxiValue); // read prox value on demand
return ProxiValue;
}
///////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////// MOTOR ///////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
// Calculo do Duty tem de ser revisto, o motor aguenta 6 V e o max definido aqui ronda os 4.2 V
// consultar pag 39 e 95
/**
* Sets speed and direction of the left motor.
*
* @param Dir - Direction of movement, 0 for back, or 1 for fron
* @param Speed - Percentage of speed of the motor (1..100)
*
* Note: Because of differences in the motors they need to be calibrated, test the robot going front and back
* at different speeds and see if it makes a straigth line
*/
void leftMotor(short int Dir,short int Speed)
{
float Duty;
if(Dir==1) {
q_pha_mot_lef=0; //Andar em frente
if(Speed>1000) //limite de segurança
Speed=1000;
if(Speed>0) {
Duty=Speed*.082 +35; // 35 = minimo para o motor rodar
q_sleep_mot_lef=1; //Nano Sleep Motor Left
pwm_mot_lef.pulsewidth_us(Duty*5);
} else {
q_sleep_mot_lef=0;
}
}
if(Dir==0) {
q_pha_mot_lef=1; //Andar para tras
if(Speed>1000) //limite de segurança
Speed=1000;
if(Speed>0) {
Duty=Speed*.082 +35; // 35 = minimo para o motor rodar
q_sleep_mot_lef=1; //Nano Sleep Motor Left
pwm_mot_lef.pulsewidth_us(Duty*5);
} else {
q_sleep_mot_lef=0;
}
}
}
/**
* Sets speed and direction of the right motor.
*
* @param Dir - Direction of movement, 0 for back, or 1 for fron
* @param Speed - Percentage of speed of the motor (1..100)
*
* Note: Because of differences in the motors they need to be calibrated, test the robot going front and back
* at different speeds and see if it makes a straigth line
*/
void rightMotor(short int Dir,short int Speed)
{
float Duty;
if(Dir==1) {
q_pha_mot_rig=0; //Andar em frente
if(Speed>1000) //limite de segurança
Speed=1000;
if(Speed>0) {
Duty=Speed*.082 +35; // 35 = minimo para o motor rodar
q_sleep_mot_rig=1; //Nano Sleep Motor Right
pwm_mot_rig.pulsewidth_us(Duty*5);
} else {
q_sleep_mot_rig=0;
}
}
if(Dir==0) {
q_pha_mot_rig=1; //Andar para tras
if(Speed>1000) //limite de segurança
Speed=1000;
if(Speed>0) {
Duty=Speed*.082 +35; // 35 = minimo para o motor rodar
q_sleep_mot_rig=1; //Nano Sleep Motor Right
pwm_mot_rig.pulsewidth_us(Duty*5);
} else {
q_sleep_mot_rig=0;
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////// ENCODER ///////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
/**
* Reads Position of left magnetic encoder.
*
* @return The absolute position of the left wheel encoder (0..4095)
*/
long int read_L_encoder()
{
char data_r_2[5];
i2c.start();
i2c.write(0x6C);
i2c.write(0x0C);
i2c.read(0x6D,data_r_2,4,0);
i2c.stop();
short int val1=data_r_2[0];
short int val2=data_r_2[1];
val1=(val1&0xf)*256;
long int final=(val2+val1);
return final;
}
/**
* Reads Position of right magnetic encoder.
*
* @return The absolute position of the right wheel encoder (0..4095)
*/
long int read_R_encoder()
{
char data_r_2[5];
i2c1.start();
i2c1.write(0x6C);
i2c1.write(0x0C);
i2c1.read(0x6D,data_r_2,4,0);
i2c1.stop();
short int val1=data_r_2[0];
short int val2=data_r_2[1];
val1=(val1&0xf)*256;
long int final=(val2+val1);
return final;
}
/**
* Calculates and returns the value of the right "incremental" encoder.
*
* @return The value of "tics" of the right encoder since it was initialized
*/
long int incremental_R_encoder()
{
short int next_R=read_R_encoder(); // Reads curent value of the encoder
short int dif=next_R-prev_R; // Calculates the diference from last reading
if(dif>3000) { // Going back and pass zero
total_R=total_R-4096+dif;
}
if(dif<3000&&dif>0) { // Going front
total_R=total_R+dif;
}
if(dif<-3000) { // Going front and pass zero
total_R=total_R+4096+dif;
}
if(dif>-3000&&dif<0) { // going back
total_R=total_R+dif;
}
prev_R=next_R; // Sets last reading for next iteration
return total_R;
}
/**
* Calculates and returns the value of the left "incremental" encoder.
*
* @return The value of "tics" of the left encoder since it was initialized
*/
long int incremental_L_encoder()
{
short int next_L=read_L_encoder(); // Reads curent value of the encoder
short int dif=-next_L+prev_L; // Calculates the diference from last reading
if(dif>3000) { // Going back and pass zero
total_L=total_L-4096+dif;
}
if(dif<3000&&dif>0) { // Going front
total_L=total_L+dif;
}
if(dif<-3000) { // Going front and pass zero
total_L=total_L+4096+dif;
}
if(dif>-3000&&dif<0) { // going back
total_L=total_L+dif;
}
prev_L=next_L; // Sets last reading for next iteration
return total_L;
}
/**
* Calculate the value of both encoder "incremental" every 10 ms.
*/
void timer_event() //10ms interrupt
{
timeout.attach(&timer_event,0.01);
if(flag==0) {
incremental_R_encoder();
incremental_L_encoder();
}
Odometria();
return;
}
/**
* Set the initial position for the "incremental" enconder and "starts" them.
*/
void initEncoders()
{
prev_R=read_R_encoder();
prev_L=read_L_encoder();
timeout.attach(&timer_event,0.01);
}
/**
* Returns to the user the value of the right "incremental" encoder.
*
* @return The value of "tics" of the right encoder since it was initialized
*/
long int R_encoder()
{
wait(0.0001);
return total_R;
}
/**
* Returns to the user the value of the right "incremental" encoder.
*
* @return The value of "tics" of the right encoder since it was initialized
*/
long int L_encoder()
{
wait(0.0001);
return total_L;
}
///////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////// BATTERY ///////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
/**
* Reads adc of the battery.
*
* @param addr - Address to read
* @return The voltage of the batery
*/
long int read16_mcp3424(char addr)
{
char data[4];
i2c1.start();
i2c1.read(addr,data,3);
i2c1.stop();
return(((data[0]&127)*256)+data[1]);
}
/**
* Reads adc of the battery.
*
* @param n_bits - Resolution of measure
* @param ch - Chose value to read, if voltage or current of solar or batery
* @param gain -
* @param addr - Address to write to
*/
void write_mcp3424(int n_bits, int ch, int gain, char addr) //chanel 1-4 write -> 0xD0
{
int chanel_end=(ch-1)<<5; //shift left
char n_bits_end=0;
if(n_bits==12) {
n_bits_end=0;
} else if(n_bits==14) {
n_bits_end=1;
} else if(n_bits==16) {
n_bits_end=2;
} else {
n_bits_end=3;
}
n_bits_end=n_bits_end<<2; //shift left
char data[1];
data[0]= (char)chanel_end | (char)n_bits_end | (char)(gain-1) | 128;
i2c1.start();
i2c1.write(addr,data,1);
i2c1.stop();
}
/**
* Reads adc of the battery.
*
* @return The voltage of the batery
*/
float value_of_Batery()
{
float R1=75000.0;
float R2=39200.0;
float R3=178000.0;
float Gain=1.0;
write_mcp3424(16,3,1,0xd8);
float cha3_v2=read16_mcp3424(0xd9); //read voltage
float Vin_v_battery=(((cha3_v2*2.048)/32767))/Gain;
float Vin_b_v_battery=(-((-Vin_v_battery)*(R1*R2 + R1*R3 + R2*R3))/(R1*R2));
Vin_b_v_battery=(Vin_b_v_battery-0.0)*1.00268;
return Vin_b_v_battery;
}
///////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////// Sonar ////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
// Commands of operation with ultrasonic module
// WRITE OPTION:
// ENABLE DC DC CONVERTER - 0x0C;
// DISABLE DC DC CONVERTER - 0x0B;
// START MEASURE LEFT SENSOR - 0x0A;
// START MEASURE FRONT SENSOR - 0x09;
// START MEASURE RIGHT SENSOR - 0x08;
// SENSORS ALWAYS MEASURE ON - 0x07;
// SENSORS ALWAYS MEASURE OFF - 0x06;
// READ OPTION:
// GET MEASURE OF LEFT SENSOR - 0x05;
// GET MEASURE OF FRONT SENSOR - 0x04;
// GET MEASURE OF IGHT SENSOR - 0x03;
// GET STATUS SENSORS ALWAYS MEASURE - 0x02;
// GET STATUS DC DC CONVERTER - 0x01;
void enable_dc_dc_boost()
{
char data[1];
data[0]= 0x0C;
wait_ms(1);
i2c1.start();
i2c1.write(0x30,data,1);
i2c1.stop();
i2c1.start();
i2c1.write(0x30,data,1);
i2c1.stop();
}
void disable_dc_dc_boost()
{
char data[1];
data[0]= 0x0B;
wait_ms(1);
i2c1.start();
i2c1.write(0x30,data,1);
i2c1.stop();
}
void start_read_left_sensor()
{
char data[1];
data[0]= 0x0A;
wait_ms(1);
i2c1.start();
i2c1.write(0x30,data,1);
i2c1.stop();
}
void start_read_front_sensor()
{
char data[1];
data[0]= 0x09;
wait_ms(1);
i2c1.start();
i2c1.write(0x30,data,1);
i2c1.stop();
}
void start_read_right_sensor()
{
char data[1];
data[0]= 0x08;
wait_ms(1);
i2c1.start();
i2c1.write(0x30,data,1);
i2c1.stop();
}
void measure_always_on() // left, front, right
{
char data[1];
data[0]= 0x07;
wait_ms(1);
i2c1.start();
i2c1.write(0x30,data,1);
i2c1.stop();
}
void measure_always_off()
{
char data[1];
data[0]= 0x06;
wait_ms(1);
i2c1.start();
i2c1.write(0x30,data,1);
i2c1.stop();
}
/**
* Returns left sensor value
*/
static unsigned int get_distance_left_sensor()
{
static char data_r[3];
static unsigned int aux;
flag=1;
data_r[0]= 0x05;
wait_ms(1);
i2c1.start();
i2c1.write(0x30,data_r,1);
i2c1.stop();
wait_ms(10);
i2c1.start();
i2c1.read(0x31,data_r,2,0);
i2c1.stop();
aux=(data_r[0]*256)+data_r[1];
flag=0;
return aux;
// sensor_left=aux;
// pc.printf("\nDistance Left Sensor: %u mm",aux); //0 - 2500mm
}
/**
* Returns front sensor value
*/
static unsigned int get_distance_front_sensor()
{
static char data_r[3];
static unsigned int aux;
flag=1;
data_r[0]= 0x04;
wait_ms(1);
i2c1.start();
i2c1.write(0x30,data_r,1);
i2c1.stop();
wait_ms(10);
i2c1.start();
i2c1.read(0x31,data_r,2,0);
i2c1.stop();
aux=(data_r[0]*256)+data_r[1];
flag=0;
return aux;
// sensor_front=aux;
// pc.printf("\nDistance Front Sensor: %u mm",aux); //0 - 2500mm
}
/**
* Returns right sensor value
*/
static unsigned int get_distance_right_sensor()
{
static char data_r[3];
static unsigned int aux;
flag=1;
data_r[0]= 0x03;
wait_ms(1);
i2c1.start();
i2c1.write(0x30,data_r,1);
i2c1.stop();
wait_ms(10);
i2c1.start();
i2c1.read(0x31,data_r,2,0);
i2c1.stop();
aux=(data_r[0]*256)+data_r[1];
flag=0;
return aux;
// sensor_right=aux;
// pc.printf("\nDistance Right Sensor: %u \r",aux); //0 - 2500mm
}
void get_status_always_measure()
{
static char data_r[3];
static unsigned int aux;
data_r[0]= 0x02;
wait_ms(1);
i2c1.start();
i2c1.write(0x30,data_r,1);
i2c1.stop();
wait_ms(10);
i2c1.start();
i2c1.read(0x31,data_r,2,0);
i2c1.stop();
aux=data_r[0];
pc.printf("\nStatus of read always on/off: %u ",aux); //0 (off) - 1 (on)
}
void get_status_dcdc_converter()
{
static char data_r[3];
static unsigned int aux;
data_r[0]= 0x01;
wait_ms(1);
i2c1.start();
i2c1.write(0x30,data_r,1);
i2c1.stop();
wait_ms(10);
i2c1.start();
i2c1.read(0x31,data_r,2,0);
i2c1.stop();
aux=data_r[0];
pc.printf("\nStatus of DC/DC Converter: %u ",aux); //0 (off) - 1 (on)
}
///////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////// MISC. ////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
/**
* Initializes the necessary robot pins
*/
void init_robot_pins()
{
//SAIDAS DIGITAIS (normal)
//q_pha_mot_rig=0; //Phase Motor Right
//q_sleep_mot_rig=0; //Nano Sleep Motor Right
//q_pha_mot_lef=0; //Phase Motor Left
//q_sleep_mot_lef=0; //Nano Sleep Motor Left
//q_pow_ena_i2c_p=0; //Power Enable i2c FET P
//q_pow_ena_mic_p=0; //Power enable Micro FET P
//q_pow_as5600_n=1; //AS5600 Power MOSFET N
//q_pow_as5600_p=0; //AS5600 Power MOSFET P
//q_pow_spi=0; //SPI Power MOSFET P
//q_ena_mppt=0; //Enable MPPT Control
//q_boost_ps=1; //Boost Power Save
//q_tca9548_reset=1; //Reset TCA9548
//SAIDAS DIGITAIS (normal)
q_pha_mot_rig=0; //Phase Motor Right
q_sleep_mot_rig=0; //Nano Sleep Motor Right
q_pha_mot_lef=0; //Phase Motor Left
q_sleep_mot_lef=0; //Nano Sleep Motor Left
q_pow_ena_i2c_p=0; //Power Enable i2c FET P
q_pow_ena_mic_p=0; //Power enable Micro FET P
q_pow_as5600_p=0; //AS5600 Power MOSFET P
// q_pow_spi=0; //SPI Power MOSFET P
q_pow_as5600_n=1; //AS5600 Power MOSFET N
q_ena_mppt=0; //Enable MPPT Control
q_boost_ps=1; //Boost Power Save
q_tca9548_reset=1; //Reset TCA9548
//Leds caso seja saida digital:
q_led_red_fro=1; //Led Red Front (led off)
q_led_gre_fro=1; //Led Green Front (led off)
q_led_blu_fro=1; //Led Blue Front (led off)
q_led_red_rea=1; //Led Red Rear (led off)
q_led_gre_rea=1; //Led Green Rear (led off)
q_led_blu_rea=1; //Led Blue Rear (led off)r
//********************************************************************
//SAIDAS DIGITAIS (pwm)
//PWM Enable Motor Right
pwm_mot_rig.period_us(500);
pwm_mot_rig.pulsewidth_us(0);
//PWM Enable Motor Left
pwm_mot_lef.period_us(500);
pwm_mot_lef.pulsewidth_us(0);
//Buzzer PWM
pwm_buzzer.period_us(500);
pwm_buzzer.pulsewidth_us(0);
//LED white
pwm_led_whi.period_us(500);
pwm_led_whi.pulsewidth_us(0);
}
/**
* Initializes all the pins and all the modules necessary
*/
void initRobot(void)
{
init_robot_pins();
enable_dc_dc_boost();
//init_Infrared();
//initEncoders();
enable_dc_dc_boost();
wait_ms(100); //wait for read wait(>=150ms);
measure_always_on();
float value = value_of_Batery();
pc.printf("Initialization Successful \n\r");
pc.printf("Battery level: %f \n\r",value);
if(value < 3.0) {
pc.printf(" WARNING: BATTERY NEEDS CHARGING ");
}
// float level = value_of_Batery();
// sendValue(int(level*100));
}
////////////////////////////////////////////////////
/**
* Updates the position and orientation of the robot based on the data from the encoders
*
* Note: Needs to be calibrated for each robot, in this case the radius of the whells is 3.55
* and the distance between them is 7.4
*/
void Odometria()
{
long int ticks1d=R_encoder();
long int ticks1e=L_encoder();
long int D_ticks=ticks1d - ticks2d;
long int E_ticks=ticks1e - ticks2e;
ticks2d=ticks1d;
ticks2e=ticks1e;
float D_cm= (float)D_ticks*((3.25*3.1415)/4096);
float L_cm= (float)E_ticks*((3.25*3.1415)/4096);
float CM=(D_cm + L_cm)/2;
theta +=(D_cm - L_cm)/7.18;
theta = atan2(sin(theta), cos(theta));
// meter entre 0
X += CM*cos(theta);
Y += CM*sin(theta);
}
