-
remi.greub authoredremi.greub authored
labyrinth.c 8.87 KiB
/**
* Name : tp1_labyrinth.c
* Author : VP
* Date : 23.10.2017
* Description : Labyrinth (TP1). Master implementation must contain:
* - 5 balls management, 1 of the master controlled by the local accelerometer
* - 1 ball controlled by the slave (accelerometer of the slave board)
* - 3 balls with random accelerations
* - FreeRTOS used in cooperative mode
* - use of global variables allowed
* Only the slave acceleration is given by the slave. All ball positions are
* managed by the master.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <math.h>
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
#include "lcd.h"
#include "accelerometer.h"
#include "ethernet_mgt.h"
#include "tools.h"
#include "custom_rand.h"
#include "traces_ref.h"
#define NUMBER_OF_BALLS 5 // min 1
#define BALL_DISP_PERIOD 20 // ms
#define BOT1_BALL_DISP_PERIOD 30 // ms
#define BOT2_BALL_DISP_PERIOD 50 // ms
#define BOT3_BALL_DISP_PERIOD 45 // ms
#define SPEED_MAX 5.
#define BALL_RADIUS 5
#define BOT1_BALL_RADIUS 7
#define BOT2_BALL_RADIUS 8
#define BOT3_BALL_RADIUS 8
#define REBOUND_FACTOR 0.9 // speed ratio after a rebound
#define PI 3.141592
#define LCD_YELLOW (LCD_GREEN | LCD_RED)
#define GOAL_H_WALL (LCD_MAX_WIDTH-(2*BALL_RADIUS+1+WALL_WIDTH))
#define GOAL_V_WALL (LCD_MAX_HEIGHT-(2*BALL_RADIUS+1+WALL_WIDTH)-1)
#define NUM_THREADS 5
// Ball identifiers
enum {
NONE = -1, // NONE is used if ball has reached the goal (winner field)
MASTER_BALL,
SLAVE_BALL,
BOT1_BALL,
BOT2_BALL,
BOT3_BALL
};
// ball descriptor
typedef struct {
int thread_id;
object_t ball;
} ball_param_th_t;
static coord_fx_t labyrinth_points[]={
{80,280},{40,280},{40,190},{END_OF_LINE,LCD_WHITE},
{40,100},{150,100},{150,160},{70,160},{END_OF_LINE,LCD_WHITE},
{0,160},{40,160},{END_OF_LINE,LCD_WHITE},
{70,190},{180,190},{180,80},{END_OF_LINE,LCD_WHITE},
{210,100},{238,100},{END_OF_LINE,LCD_WHITE},
{180,220},{238,220},{END_OF_LINE,LCD_WHITE},
{0,40},{100,40},{END_OF_LINE,LCD_WHITE},
{140,40},{237,40},{END_OF_LINE,LCD_WHITE},
{120,220},{120,300},{END_OF_LINE,LCD_GREEN},
{GOAL_H_WALL-2*BALL_RADIUS,GOAL_V_WALL},{LCD_MAX_WIDTH-1,GOAL_V_WALL},{END_OF_LINE,LCD_GREEN},
{GOAL_H_WALL-4*BALL_RADIUS-WALL_WIDTH-1,LCD_MAX_HEIGHT-WALL_WIDTH},{GOAL_H_WALL-4*BALL_RADIUS-WALL_WIDTH-1,GOAL_V_WALL},{END_OF_WALLS,END_OF_WALLS}
};
/* Description: Callback of ethernet module. This function is called when a message is received
* Parameters: data: pointer on data received
* len: length of the data [bytes]
*/
void slave_info_rx(void *data, int len)
{
// code executed when the slave sends an ethernet frame
}
void Algo_main_ball(void *params);
void Algo_bots(void *params);
void RandAccel(accel_t *accel);
int main(void)
{
accel_t ball_accel;
static ball_param_th_t ball_param_th[NUMBER_OF_BALLS]={ // balls description
{MASTER_BALL,{{10,10}, {0, 0}, BALL_RADIUS, LCD_YELLOW, BALL_DISP_PERIOD}},
{SLAVE_BALL,{{30,10}, {0, 0}, BALL_RADIUS, LCD_GREEN, BALL_DISP_PERIOD}},
{BOT1_BALL,{{200,10}, {0, 0}, BOT1_BALL_RADIUS, LCD_RED| (LCD_BLUE>>2), BOT1_BALL_DISP_PERIOD}},
{BOT2_BALL,{{70,70}, {0, 0}, BOT2_BALL_RADIUS, LCD_RED | (LCD_BLUE>>1), BOT2_BALL_DISP_PERIOD}},
{BOT3_BALL,{{200,280}, {0, 0}, BOT3_BALL_RADIUS, LCD_RED | LCD_BLUE, BOT3_BALL_DISP_PERIOD}}
};
init_rnd32(0); // initialise random generator
init_lcd(); // initialise screen
if(accel_init() != 0) // initialise accelerometer
{
printf("Accelerometer initialisation failed!\n");
return 1;
}
//ethernet_init(..., slave_info_rx); // initialise ethernet and determine its callback function
draw_labyrinth(labyrinth_points);
init_traces(115200, 1, true); // initialise traces. Line to be removed if you implement your own traces
accel_read(&ball_accel); // example: reading of the accelerometer
// creating tasks...
/*for(int i = 0; i<NUM_THREADS; i++){
}*/
xTaskCreate(Algo_main_ball, (signed portCHAR *)"Masterball",
configMINIMAL_STACK_SIZE, &ball_param_th[0], tskIDLE_PRIORITY+1,
NULL);
xTaskCreate(Algo_bots, (signed portCHAR *)"libreball1",
configMINIMAL_STACK_SIZE, &ball_param_th[2], tskIDLE_PRIORITY+1,
NULL);
vTaskStartScheduler(); // launch scheduler
LPC_TIM0->TCR = 1;
while(1);
return 1;
}
void Algo_main_ball(void *params){
ball_param_th_t *ball = (ball_param_th_t *)params;
accel_t ball_acc;
int un_ou_moins_un_x = 1, un_ou_moins_un_y = 1;
while(1){
lcd_filled_circle(ball->ball.pos.x, ball->ball.pos.y, ball->ball.radius, LCD_BLACK);
int CollisionState = test_collision(&ball->ball);
if(CollisionState != NO_COLLISION){
//ralentissement de 10% de la vitesse de la balle
ball->ball.speed.x = ball->ball.speed.x - (ball->ball.speed.x/10);
ball->ball.speed.y = ball->ball.speed.y - (ball->ball.speed.y/10);
if(CollisionState & TOUCH_LEFT){
un_ou_moins_un_x = -1;
ball->ball.pos.x += ball->ball.radius/2;
}
if(CollisionState & TOUCH_RIGHT){
un_ou_moins_un_x = -1;
ball->ball.pos.x -= ball->ball.radius/2;
}
if(CollisionState & TOUCH_UP){
un_ou_moins_un_y = -1;
ball->ball.pos.y += ball->ball.radius/2;
}
if(CollisionState & TOUCH_DOWN){
un_ou_moins_un_y = -1;
ball->ball.pos.y -= ball->ball.radius/2;
}
}else{
accel_read(&ball_acc);
ball->ball.speed.x = ((ball_acc.accel_x*0.1)+ball->ball.speed.x)*(un_ou_moins_un_x);
ball->ball.speed.y = ((ball_acc.accel_y*0.1)+ball->ball.speed.y)*(un_ou_moins_un_y);
ball->ball.pos.x = ball->ball.pos.x + ball->ball.speed.x*(un_ou_moins_un_x);
ball->ball.pos.y = ball->ball.pos.y + ball->ball.speed.y*(un_ou_moins_un_y);
un_ou_moins_un_y = 1;
un_ou_moins_un_x = 1;
}
//détection des collisions sur les bords de l'ecran LCD
if(ball->ball.pos.x <= ball->ball.radius){
ball->ball.pos.x = ball->ball.radius+1;
}
if(ball->ball.pos.y <= ball->ball.radius){
ball->ball.pos.y = ball->ball.radius+1;
}
if(ball->ball.pos.x >= LCD_MAX_WIDTH-ball->ball.radius){
ball->ball.pos.x = LCD_MAX_WIDTH-ball->ball.radius;
}
if(ball->ball.pos.y >= LCD_MAX_HEIGHT-ball->ball.radius){
ball->ball.pos.y = LCD_MAX_HEIGHT-ball->ball.radius;
}
lcd_filled_circle(ball->ball.pos.x, ball->ball.pos.y, ball->ball.radius, ball->ball.color);
vTaskDelay((portTickType)20/portTICK_RATE_MS);
}
}
void Algo_bots(void *params){
ball_param_th_t *ball = (ball_param_th_t *)params;
accel_t ball_acc;
int un_ou_moins_un_x = 1, un_ou_moins_un_y = 1;
while(1){
lcd_filled_circle(ball->ball.pos.x, ball->ball.pos.y, ball->ball.radius, LCD_BLACK);
int CollisionState = test_collision(&ball->ball);
if(CollisionState != NO_COLLISION){
//ralentissement de 10% de la vitesse de la balle
ball->ball.speed.x = ball->ball.speed.x - (ball->ball.speed.x/10);
ball->ball.speed.y = ball->ball.speed.y - (ball->ball.speed.y/10);
if(CollisionState & TOUCH_LEFT){
un_ou_moins_un_x = -1;
ball->ball.pos.x += ball->ball.radius/2;
}
if(CollisionState & TOUCH_UP){
un_ou_moins_un_y = -1;
ball->ball.pos.y += ball->ball.radius/2;
}
if(CollisionState & TOUCH_RIGHT){
un_ou_moins_un_x = -1;
ball->ball.pos.x -= ball->ball.radius/2;
}
if(CollisionState & TOUCH_DOWN){
un_ou_moins_un_y = -1;
ball->ball.pos.y -= ball->ball.radius/2;
}
}else{
RandAccel(&ball_acc);
ball->ball.speed.x = ((ball_acc.accel_x*0.1)+ball->ball.speed.x)*(un_ou_moins_un_x);
ball->ball.speed.y = ((ball_acc.accel_y*0.1)+ball->ball.speed.y)*(un_ou_moins_un_y);
ball->ball.pos.x = ball->ball.pos.x + ball->ball.speed.x*(un_ou_moins_un_x);
ball->ball.pos.y = ball->ball.pos.y + ball->ball.speed.y*(un_ou_moins_un_y);
un_ou_moins_un_y = 1;
un_ou_moins_un_x = 1;
}
//}
if(ball->ball.pos.x <= ball->ball.radius){
ball->ball.pos.x = ball->ball.radius+1;
}
if(ball->ball.pos.y <= ball->ball.radius){
ball->ball.pos.y = ball->ball.radius+1;
}
if(ball->ball.pos.x >= LCD_MAX_WIDTH-ball->ball.radius){
ball->ball.pos.x = LCD_MAX_WIDTH-ball->ball.radius;
}
if(ball->ball.pos.y >= LCD_MAX_HEIGHT-ball->ball.radius){
ball->ball.pos.y = LCD_MAX_HEIGHT-ball->ball.radius;
}
lcd_filled_circle(ball->ball.pos.x, ball->ball.pos.y, ball->ball.radius, ball->ball.color);
vTaskDelay((portTickType)20/portTICK_RATE_MS);
}
}
//random d'accélérations
void RandAccel(accel_t *accel){
float x = (float)(rnd32()%100)-50;
float y = (float)(rnd32()%100)-50;
accel->accel_x = x/100;
accel->accel_y = y/100;
//accel->accel_z = (float)(rnd32()%500)/100;
accel->magneto_x = 0;
accel->magneto_y = 0;
accel->magneto_z = 0;
accel->temperature = 0;
}