Hello! My name is RoboWalter. My main function is that you can communicate with me through Bluetooth.
I really don't like losing the connection I have with my commander because then I will roll into a wall.
I also have a display that shows my emotion when I drive. I hate to stand still so that is when I am sad,
but if I get a command to drive I become happy!
I cannot move unless you turn on the switch on my back.
If you place the cursor inside the table below and scroll to see the code it took to programme RoboWalter
/* |
* robo_walter.c |
* |
* Created: 2019-04-04 13:43:00 |
*/ |
#define F_CPU 1000000UL |
#define BAUDE_RATE 9600 |
#include <avr/interrupt.h> |
#include <avr/io.h> |
#include <util/delay.h> |
void usartInit(); |
char usartReceive(uint8_t channel); |
void usartTransmit(uint8_t channel, unsigned char data); |
void timerInit(); |
void setPulseLeftA(uint8_t pulse); |
void setPulseLeftB(uint8_t pulse); |
void setPulseRightA(uint8_t pulse); |
void setPulseRightB(uint8_t pulse); |
void leftForward(uint8_t speed); |
void leftBackwards(uint8_t speed); |
void rightForward(uint8_t speed); |
void rightBackwards(uint8_t speed); |
void oledInit(uint8_t size); |
void sendString(unsigned char *, int); |
void sendChr(unsigned char); |
void newLine(); |
void newEmpty(); |
void drawCircle(int16_t x, int16_t y, int16_t radius, int16_t color, int16_t filled); |
void drawLine(int8_t x1, int8_t y1, int8_t x2, int8_t y2, int16_t color); |
void sendSmiley(int x); |
void drawMouth(double happines); |
void init(); |
volatile uint8_t speedOffset = 0; |
volatile uint8_t currentLeftSpeed = 0; |
volatile uint8_t lastLeftSpeed = 0; |
volatile uint8_t currentRightSpeed = 0; |
volatile uint8_t lastRightSpeed = 0; |
int main(void){ |
_delay_ms(4000); |
init(); |
unsigned char stop[] = {0x00, 0x0C, 0x00, 0x00}; |
sendString(stop, sizeof(stop)); |
//PORT(A-D) write |
//PIN(A-D) read |
//OC3B = INB2 |
//OC3A = INB1 |
drawFace(10.0); |
while (1){} |
} |
void drawFace(double happiness){ |
drawCircle(64, 62, 60, 0xE1A0, 0) |
//_delay_ms(50); |
drawCircle(64, 64, 60, 0xEED2, 1) |
_delay_ms(100); |
drawCircle(35, 40, 10, 0xFFFF, 1) |
drawCircle(89, 40, 10, 0xFFFF, 1) |
//_delay_ms(50); |
unsigned char nose[] = {0x00, 0x05, 0, 8, 0x00, 58, 0x00, 58, 0x00, 54, 0x00, 58, 0x00, 70, 0x00, 74, 0x00, 70, 0x00, 70, 0x00, |
40, 0x00, 55, 0x00, 65, 0x00, 70, 0x00, 70, 0x00, 65, 0x00, 55, 0x00, 40, 0x00, 0x00} |
sendString(nose, sizeof(nose)); |
if (happiness < 0){ |
drawLine(25, 32, 48, 25, 0xE1A0); |
drawLine(103, 32, 80, 25, 0xE1A0); |
drawCircle(35, 40, 3, 0x0000, 1); |
drawCircle(89, 40, 3, 0x0000, 1); |
}else{ |
drawLine(25, 26, 48, 25, 0xE1A0) |
drawLine(103, 26, 80, 25, 0xE1A0) |
drawCircle(35, 40, 3, 0x2B1D, 1); |
drawCircle(89, 40, 3, 0x2B1D, 1); |
} |
//_delay_ms(100); |
drawMouth(happiness); |
} |
void drawMouth(double happines){ |
unsigned char init[] = {0x00, 0x05, 0, 10}; |
sendString(init, sizeof(init)); |
for(int x = 0; x < 10; x++){ |
sendChr(0x00); |
uint8_t f = (uint8_t)(30 + (68 / 9 * x)); |
sendChr(f); |
} |
for(int y = -5; y <= 5; y++){ |
if (y != 0){ |
sendChr(0x00); |
uint8_t g = 100 - (y * y / happines); |
sendChr(g); |
} |
} |
sendChr(0x00); |
sendChr(0x00); |
} |
/** |
* Initialize all variables, methods. |
*/ |
void init() { |
cli(); |
usartInit(); |
timerInit(); |
//set input for Bluetooth module input(TX) (RXD1 on atmega) |
DDRD &= ~(1 << 2); |
//Enable SLP H-brygga |
DDRA |= (1 << DDRA5); |
PORTA |= (1 << DDRA5); |
oledInit(3); |
//Set first bit in the status register (SREG) |
sei(); |
leftForward(0); |
rightForward(0); |
} |
/** ##### BLUETOOTH MODULE INTERRUPTS ##### |
* This part will run whenever we recieve something |
* from the Bluetooth module. |
*/ |
ISR(USART1_RX_vect){ |
volatile unsigned char data = UDR1; |
volatile uint8_t speed = 140; |
lastLeftSpeed = currentLeftSpeed; |
lastRightSpeed = currentRightSpeed; |
usartTransmit(1, data); |
switch(data) { |
//a left forward |
case 193: |
leftForward(speed); |
currentLeftSpeed = speed; |
break; |
//b left backwards |
case 194: |
leftBackwards(80); |
currentLeftSpeed = 80; |
break; |
//c right forward |
case 195: |
rightForward(speed i speedOffset); |
currentRightSpeed = speed + speedOffset; |
break; |
//ENTER right backwards |
case 29: |
rightBackwards(80); |
currentRightSpeed = 80; |
break; |
//, right stop |
case 92: |
leftForward(0); |
currentLeftSpeed = 0; |
break; |
//. left stop |
case 94: |
rightForward(0); |
currentRightSpeed = 0; |
break; |
//8 both stop |
case 112: |
case 120: |
rightBackwards(0); |
leftBackwards(0); |
currentRightSpeed = 0; |
currentLeftSpeed = 0; |
break; |
//9 add to speedoffset |
case 121: |
case 113: |
speedOffset += 2; |
break; |
//I add to speedoffset |
case 217: |
case 209: |
speedOffset -= 2; |
break; |
//J left fast forward |
case 218: |
case 210: |
leftForward(speed * 1.6); |
currentLeftSpeed = speed * 1.6; |
break; |
//K left slow forward |
case 219: |
case 211: |
leftForward(speed * 0.4); |
currentLeftSpeed = speed * 0.4; |
break; |
//L right fast forward |
case 220: |
rightForward(speed * 1.6); |
currentRightSpeed = speed * 1.6; |
break; |
//M right slow forward |
case 221: |
rightForward(speed * 0.4); |
currentRightSpeed = speed * 0.4; |
break; |
case 102: |
rightForward(255); |
leftForward(255); |
currentRightSpeed = 250; |
currentLeftSpeed = 250; |
break; |
} |
uint8_t max = (currentLeftSpeed > currentRightSpeed) ? currentLeftSpeed : currentRightSpeed; |
max = (max > 200) ? 180 : max; |
if(max - 79 != 0) { |
if((currentLeftSpeed != lastLeftSpeed) || (currentRightSpeed != lastRightSpeed)) { |
drawFace(100 / (max -80)); |
} |
} |
} |
//######### OLED ######### |
void oledInit(uint8_t size) { |
//unsigned char clear[] = {0xff, 0xd7}; |
unsigned char text_width[] = {0xff, 0x7c, 0x00, size}; |
unsigned char text_height[] = {0xff, 0x7b, 0x00, size}; |
unsigned char move[] = {0xff, 0xe4, 0x00, 0x00, 0x00, 0x00}; |
//send_string(clear, sizeof(clear)); |
sendString(text_width, sizeof(text_width)); |
sendString(text_height, sizeof(text_height)); |
sendString(move, sizeof(move)); |
} |
inline void sendString(unsigned char * msg, int length) { |
for(int i = 0; i < length; i++) { |
sendChr(msg[i]); |
} |
} |
void sendChr(unsigned char c){ |
while(!(UCSR0A & (1 << UDRE0))); |
UDR0 = c; |
} |
void newLine() { |
unsigned char move[] = {0xff, 0xe4, 0x00, 0x01, 0x00, 0x00}; |
sendString(move, sizeof(move)); |
} |
void newEmpty() { |
unsigned char move[] = {0xff, 0xe4, 0x00, 0x00, 0x00, 0x01}; |
sendString(move, sizeof(move)); |
} |
void drawCircle(int16_t x, int16_t y, int16_t radius, int16_t color, int filled){ |
uint8_t x1 = (uint8_t)(x % 256); |
uint8_t x2 = (uint8_t)(x >> 8); |
uint8_t y1 = (uint8_t)(y % 256); |
uint8_t y2 = (uint8_t)(y >> 8); |
uint8_t rad1 = (uint8_t)(radius % 256); |
uint8_t rad2 = (uint8_t)(radius >> 8); |
uint8_t color1 = (uint8_t)(color % 256); |
uint8_t color2 = (uint8_t)(color >> 8); |
if(filled) { |
unsigned char circledata[] = {0xff, 0xCC, x2, x1, y2, y1, rad2, rad1, color2, color1}; |
sendString(circledata, sizeof(circledata)); |
} else { |
unsigned char circledata[] = {0xff, 0xCD, x2, x1, y2, y1, rad2, rad1, color2, color1}; |
sendString(circledata, sizeof(circledata)); |
} |
} |
void drawLine(int8_t x1, int8_t y1, int8_t x2, int8_t y2, int16_t color) { |
uint8_t color1 = (uint8_t)(color % 256); |
uint8_t color2 = (uint8_t)(color >> 8); |
unsigned char linedata[] = {0xff, 0xD2, 0x00, x1, 0x00, y1, 0x00, x2, 0x00, y2, color2, color1}; |
sendString(linedata, sizeof(linedata)); |
} |
//######### DRIVE METHODS ############ |
/** |
* Drives the left motor forward with a defined speed. |
* Uses PWM to set the defined speed. |
* |
@param speed the desired speed of the motor |
**/ |
void leftForward(unit8_t speed) { |
PORTB &= ~(1 << 6); |
setPulseLeftB(0); |
setPulseLeftA(speed); |
} |
/** |
* Drives the left motor backwards with a defined speed. |
* Uses PWM to set the defined speed. |
* |
@param speed the desired speed of the motor |
**/ |
void leftBackwards(uint8_t speed) { |
setPulseLeftA(0); |
setPulseLeftB(speed); |
} |
/** |
* Drives the right motor backwards with a defined speed. |
* Uses PWM to set the defined speed. |
* |
@param speed the desired speed of the motor |
**/ |
void rightBackwards(uint8_t speed) { |
setPulseRightB(0); |
setPulseRightA(speed); |
} |
/** |
* Drives the right motor forwards with a defined speed. |
* Uses PWM to set the defined speed. |
* |
@param speed the desired speed of the motor |
**/ |
void rightForward(uint8_t speed) { |
setPulseRightA(0); |
setPulseRightB(speed); |
} |
//######### USART ######### |
/** Enables USART[0-1] with default values both |
* the oled display and Bluetooth module |
*/ |
void usartInit() { |
//#### USART0 OLED DISPLAY |
//Nollstället värden |
UCSR0B = 0X00; |
UCSR0C = 0X00; |
//Baud rate |
UBRR0 = 6; |
//Enable transmitter, receiver |
UCSR0B |= (1 << RXEN0) | (1 << TXEN0); |
//8-bits (011) |
UCSR0C |= (1 << UCSZ00) | (1 << UCSZ01); |
//UCSR0B &= ~(1 << UCSZ02); |
//1 STOP BIT (0) |
//UCSR0C &= ~(1 << USBS0); |
//#### USART1 BLUETOOTH MODULE |
//Nollställer värden |
UCSR1B = 0x00; |
UCSR1C = 0x00; |
//9600bps, 8-bits, 1 stop bit, parity none |
//Baud rate 9600 |
UBRR1 = ((F_CPU / (BAUDE_RATE * 16UL)) - 1); |
//Enable transmitter, receiver |
UCSR1B |= (1 << RXEN1) | (1 << TXEN1); |
//Enables receiver, transmitter interrupts |
UCSR1B |= (1 << RXCIE1); |
//8-bits (011) |
UCSR1C |= (1 << UCSZ00) | (1 << UCSZ01); |
//UCSR1B &= ~(1 << UCSZ02); |
//1 stop bit (0) |
//UCSR1C &= ~(1 << USBS1); |
//Pairty none (00) |
//UCSR1C &= ~(1 << UPM11); |
//UCSR1C &= ~(1 << UPM10); |
} |
/** Returns the received data from USART buffert.*/ |
char usartReceive(uint8_t channel){ |
switch(channel){ |
case 0: |
//Wait as long as no data in receiver buffer |
while(!(UCSR0A & (1 << RXC0))); |
//Return data from buffer |
return UDR0; |
case 1: |
////TODO has to be checked |
//Wait as long as no data in receiver buffer |
while(!(UCSR1A & (1 << RXC1))); |
//Return data from buffer |
return UDR1; |
default: |
return '_'; |
} |
} |
/** Sends the data to the USART channel. */ |
void usartTransmit(uint8_t channel, unsigned char data){ |
switch(channel){ |
case 0: |
//Wait as long as there is data in buffer |
while(!(UCSR0A & (1 << UDRE0))); |
//Send data 0xC6 |
UDR0 = data; |
break; |
case 1: |
//Wait as long as there is data in buffer |
while(!(UCSR1A & (1 << UDRE1))); |
//Send data 0xCE |
UDR1 = data; |
break; |
} |
} |
//##### TIMERS FOR PWM ##### |
/** Timer/counter for PWM*/ |
void timerInit(){ |
//###### TIMER 1, 3 ###### |
//Control register A |
//Compare output mode selected with COM3A1 |
//#### Motor left |
//Clear OC3A on compare match |
TCCR3A |= (1 << COM3A1); |
//Clear OC3B on compare match (1-0) |
TCCR3A |= (1 << COM3B1); |
//OC3A-B is output |
DDRB |= (1 << 6) | (1 << 7); |
//#### Motor right |
//Clear OC1A on compare match |
TCCR1A |= (1 << COM1A1); |
//Clear OC1B on compare match (1-0) |
TCCR1A |= (1 << COM1B1); |
//O1A-B is output |
DDRB |= (1 << 4) | (1 << 5); |
//Fast PWM with ICR3 (1-1-1-0) |
//ICR3 is the top, at this value the timer will restart |
TCCR3A |= (1 << WGM31); |
TCCR3B |= (1 << WGM32) | (1 << WGM33); |
//Prescaler appropriate divison factor is used (1-0-1) |
TCCR3B |= (1 << CS31) | (1 << CS30); |
//Fast PWM with ICR1 (1-1-1-0) |
//ICR1 is the top, at this value the timer will restart |
TCCR1A |= (1 << WGM11); |
TCCR1B |= (1 << WGM12) | (1 << WGM13); |
//Prescaler appropriate divison factor is used (1-0-1) |
TCCR1B |= (1 << CS11) | (1 << CS10); |
//Sets the eriod of the cycle for both timer 3 and 1 |
ICR3 = 255; |
ICR1 = 255; |
} |
/** Sets the pulse for forward speed of the left motor*/ |
void setPulseLeftA(uint8_t pulse){ |
//Output compare register OCR3A |
OCR3A = pulse; |
} |
/** Sets the pulse for backwards speed of the left motor*/ |
void setPulseLeftB(uint8_t pulse){ |
//Output compare register OCR3B |
OCR3B = pulse; |
} |
/** Sets the pulse for forward speed of the right motor*/ |
void setPulseRightA(uint8_t pulse){ |
//Output compare register OCR1A |
OCR1A = pulse; |
} |
/** Sets the pulse for backwards speed of the right motor*/ |
void setPulseRightB(uint8_t pulse){ |
//Output compare register OCR1B |
OCR1B = pulse; |
} |
Here is a picture of the curcuit of our project - RoboWalter