PID Line follower with tank treads - c

I have made a (pretty bad) line follower.
Here is a sketch to roughly know the shape of the robot and location of the treads and sensors
[-] 0 0 [-] // 0 = color sensor
[-]------[-] // - = robot body
[-]------[-] // [-] = tank tread
[-] [-]
Here's what it does:
get Red, Green & Blue, make average of sensor 1 readings, do the same for 2
subtract to get value
this value will go through the PID part
steer with calculated steering
repeat (all of this is in a loop)
I use RGB and not reflected intensity (which is what is commonly used), because sometimes I need to detect if there's green color under the sensor (if there is, turn).
The real problem comes with the steering part. Unfortunately, it only accelerates a motor, meaning that in very tight turns we just lose the line.
Optimally, it should compensate a bit with the other motor (maybe going in the other direction?), but I am not sure how to calculate the speed of the motor, nor how to enforce this very strict line following policy.
Here is the code (I am also very grateful for any kind of tips on how to clean up the code! This is my first project in C :D ). I am not asking to read it all (it is pretty long), you could also just look at the steering function, and work your way back to rawFollowLine, this should hopefully shorten the code.
void rawFollowLine(int speed, float Kp, float Ki, float Kd){
_checkInit();
set_sensor_mode(sn_lx_color, "RGB-RAW");
set_sensor_mode(sn_rx_color, "RGB-RAW");
//printAllSensors();
int wasBlackCounter = 0;
int wasBlack = 0;
int lastBlack = 0;
for (int i = 0; i < 2000; i++)
{
if (isTerminating == 1)
{
killMotors(0);
break;
}
int greenCheck = rawGreenCheck(&wasBlack, &wasBlackCounter, &lastBlack);
if (wasBlack == 1){
wasBlackCounter++;
if (wasBlackCounter > 50){
wasBlackCounter = 0;
wasBlack = 0;
}
}
if (greenCheck == 1)
{
// lx is green
killMotors(1);
usleep(400 * 1000);
drive(200, 70);
waitIfMotorIsRunning();
killMotors(1);
pivotTurn(-90);
}
else if (greenCheck == 2)
{
// rx is green
killMotors(1);
usleep(400 * 1000);
drive(200, 70);
waitIfMotorIsRunning();
killMotors(1);
pivotTurn(90);
}
else if (greenCheck == 3)
{
// both rx and lx are green
killMotors(1);
turn(180);
}
else if (greenCheck == 5)
{
if(lastBlack == 2)
{
lastBlack = 0;
drive(100, -200);
//pivotTurn(50);
}
else if (lastBlack == 1)
{
lastBlack = 0;
drive(100, -200);
//pivotTurn(-50);
} else {
pidLineRaw(speed, Kp, Ki, Kd, &lastBlack);
}
}
else
{
pidLineRaw(speed, Kp, Ki, Kd, &lastBlack);
}
}
killMotors(1);
}
int rawGreenCheck(int *wasBlack, int *wasBlackCounter, int *lastBlack)
{
// Some documentation
// return nums:
// 3 = double green
// 2 = right green
// 1 = left green
// 0 = no green
int lx_red;
int lx_green;
int lx_blue;
int rx_red;
int rx_green;
int rx_blue;
get_sensor_value(0, sn_lx_color, &lx_red);
get_sensor_value(0, sn_rx_color, &rx_red);
get_sensor_value(1, sn_lx_color, &lx_green);
get_sensor_value(1, sn_rx_color, &rx_green);
get_sensor_value(2, sn_lx_color, &lx_blue);
get_sensor_value(2, sn_rx_color, &rx_blue);
//printf("rx_red %d\n", rx_red);
rx_red = (rx_red * rx_ratio_r);
rx_green = (rx_green * rx_ratio_g);
rx_blue = (rx_blue * rx_ratio_b);
//printf("rx_red (again) %d\n", rx_red);
if(
lx_red < 55 &&
lx_green > 90 &&
lx_blue < 55 &&
rx_red < 55 &&
rx_green > 90 &&
rx_blue < 55
)
{
// rx and lx see green
if (*wasBlack == 1)
{
// Apparently we crossed an intersection!
printf("Apparently we crossed an intersection!\n");
// We need to go straight.
*wasBlack = 0;
*wasBlackCounter = 0;
return 0;
}
else
{
return 3;
}
}
else if(lx_red < 55 && lx_green > 90 && lx_blue < 55)
{
// lx sees green
return 1;
}
else if(rx_red < 55 && rx_green > 90 && rx_blue < 55)
{
// rx sees green
return 2;
}
else if(rx_red < 50 && rx_green < 50 && rx_blue < 50 && lx_red < 50 && lx_green < 50 && lx_blue < 50)
{
// rx and lx see black
// this is needed if the intersection has the green tiles after the black line
printf("We are on the line? Is this an intersection?\n");
*wasBlack = 1;
return 0;
}
else if(lx_red < 55 && lx_green < 55 && lx_blue < 55)
{
// lx = right sees black
// this is needed if the intersection has the green tiles after the black line
//printf("We are on the line? Is this an intersection?\n");
killMotor(1, motor[R]);
rotateTillBlack(motor[L], sn_rx_color);
//printf("ASS2\n");
return 0;
}
else if(rx_red < 55 && rx_green < 55 && rx_blue < 55)
{
// rx = left sees black
killMotor(1, motor[L]);
rotateTillBlack(motor[R], sn_lx_color);
//printf("ASS1\n");
return 0;
}
//*lx_color_status = 0;
//*rx_color_status = 0;
*lastBlack = 0;
return 0;
}
void pidLineRaw(int speed, float Kp, float Ki, float Kd, int *lastBlack)
{
int red_lx_color;
int red_rx_color;
int green_lx_color;
int green_rx_color;
int blue_lx_color;
int blue_rx_color;
int lx_color;
int rx_color;
int last_error = 0;
int integral = 0;
int derivative = 0;
//float Kp = 0.1;
//float Ki = 0;
//float Kd = 0;
//set_sensor_mode(sn_lx_color, "COL-REFLECT");
//set_sensor_mode(sn_rx_color, "COL-REFLECT");
get_sensor_value(0, sn_lx_color, &red_lx_color);
get_sensor_value(0, sn_rx_color, &red_rx_color);
get_sensor_value(1, sn_lx_color, &green_lx_color);
get_sensor_value(1, sn_rx_color, &green_rx_color);
get_sensor_value(2, sn_lx_color, &blue_lx_color);
get_sensor_value(2, sn_rx_color, &blue_rx_color);
lx_color = (red_lx_color + green_lx_color+ blue_lx_color)/3;
rx_color = ( (red_rx_color*rx_ratio_r) + (green_rx_color*rx_ratio_g) + (blue_rx_color*rx_ratio_b))/3;
if(*lastBlack == 0)
{
int error = lx_color - rx_color;
integral = integral + error;
derivative = error - last_error;
last_error = error;
int steering_val = (error * Kp) + (integral * Ki) + (derivative * Kd);
// printf("error: %d\nsteering: %d\n",error, steering_val);
move_steering(-steering_val, speed, 1, 0);
} else if (*lastBlack == 1)
{
printf("lx_color_status\n");
move_steering(35, speed, 1, 0);
move_steering(-2, speed, 1, 0);
}
else if (*lastBlack == 2)
{
printf("rx_color_status\n");
move_steering(-35, speed, 1, 0);
move_steering(2, speed, 1, 0);
}
else
{
printf("HMMM: %d\n", *lastBlack);
exit(666);
}
}
static void _getSteeringSpeed(int speed, int *lx_speed, int *rx_speed, int steering)
{
if(steering > 100 || steering < -100)
{
printf("Yo wtf steering is %d\n", steering);
}
else
{
int speed_factor = (50 - abs(steering)) / 50;
*lx_speed = speed;
*rx_speed = speed;
if(steering >= 0)
{
*rx_speed = *rx_speed * speed_factor;
}
else
{
*lx_speed = *lx_speed * speed_factor;
}
}
}
Some parts are omitted, yes, they are not required to solve the problem.
I am also extremely sorry as there might be unused variables and such. I am working on refactoring the project, I'll update the post when I'm done.
So, summing everything up, I need to make sure that the steering part properly turns and follows the line. How do I do that? Is the code that I wrote even suitable? I'm guessing the steering itself might need some sort of feedback loop, to check if it's on the line?

Related

Convolution function gives segmentation error while getting pixel value of relative image coordinates

I'm trying to write a convolution function in C for my computer vision study.
In this function, every pixel in the convolved image is a sum of product of original image and filter kernel like in this image and this gif.
In the code below pixel values are float. get_pixel() function gets the pixel value at given indexes. set_pixel() function sets the value to given indexes.
image convolve(image im, image filter) {
// imx, imy, imc: indexes of image pixels
// fix, fiy: indexes of filter pixels
// rx, ry: relative indexes of pixels
image convolved_img = make_image(im.w, im.h, im.c); // image with same dimensions
float value = 0; // pixel value
int oxo = floor(filter.w / 2); // half of the kernel width
int xox = floor(filter.h / 2); // half of the kernel height
// Convolution Loop
for(int imc = 0; imc < im.c; imc++) { // for every channel
for(int imx = 0; imx < im.w; imx++) {
for(int imy = 0; imy < im.h; imy++) { // for every pixel
value = 0;
for(int fix = 0; fix < filter.w; fix++) {
for(int fiy = 0; fiy < filter.h; fiy++) {
int rx = imx - oxo + fix;
int ry = imy - xox + fiy;
value += get_pixel(filter, fix, fiy, 0) * get_pixel(im, rx, ry, imc);
}
}
set_pixel(convolved_img, imx, imy, imc, value);
}
}
}
return convolved_img;
}
I'm getting segmentation fault (core dumped) error. After debugging I realized its because of line:
value += get_pixel(filter, fix, fiy, 0) * get_pixel(im, rx, ry, imc);
When I gave fixed values of rx and ry, the program executes successfully. Inside the loop I printed the values of imx, imy, fix, fiy, rx, ry and everything works until a portion of the image has processed; after uncertain time of loop then program crushes without any reason.
I'm sure that it cannot be a index bounds related because I truncated indexes inside get_pixel() function below which I get stored value from a long array of floats.
float get_pixel(image im, int x, int y, int c) {
if(x > im.w) {x = im.w;}
else if(y > im.h) {y = im.h;}
else if(c > im.c) {c = im.c;}
else if(x < 0) {x = 0;}
else if(y < 0) {y = 0;}
else if(c < 0) {c = 0;}
int index = (c * (im.h * im.w)) + (y * im.w) + x;
return im.data[index];
}
Here is my thought about this operation as pseudo-code:
create convolved_image with same dimensions
for every pixel (imx, imy) in image {
float value = 0;
for every pixel (fix, fiy) in filter {
// calculate relative pixel coordinates
int rx = imx - (filter / 2) + fix;
int ry = imy - (filter / 2) + fiy;
value += filter(fix, fiy) * image(rx, ry);
}
set pixel of convolved_image to value
}
Am I missing something? What is the fault in my approach? Or is there a better way for this operation?
This is clearly an out of bounds access:
for(int fix = 0; fix < filter.w; fix++) {
for(int fiy = 0; fiy < filter.h; fiy++) {
int rx = imx - oxo + fix;
int ry = imy - xox + fiy;
value += get_pixel(filter, fix, fiy, 0) * get_pixel(im, rx, ry, imc);
}
}
With imx going up to im.x and fix going up to 2*oxo you are clearly larger than im.x. Same for imy.
You try to limit the range but that is not correct:
float get_pixel(image im, int x, int y, int c) {
if(x > im.w) {x = im.w;}
else if(y > im.h) {y = im.h;}
else if(c > im.c) {c = im.c;}
else if(x < 0) {x = 0;}
else if(y < 0) {y = 0;}
else if(c < 0) {c = 0;}
int index = (c * (im.h * im.w)) + (y * im.w) + x;
return im.data[index];
}
You forgot that all parameters can be wrong. You stop after first.
Also you limit to size+1 which also is wrong.
Change like this:
float get_pixel(image im, int x, int y, int c) {
if(x >= im.w) {x = im.w-1;}
else if(x < 0) {x = 0;}
if(y >= im.h) {y = im.h-1;}
else if(y < 0) {y = 0;}
if(c >= im.c) {c = im.c-1;}
else if(c < 0) {c = 0;}
int index = (c * (im.h * im.w)) + (y * im.w) + x;
return im.data[index];
}

Pattern for action decision

I am writing maze generator and at the some point I have to choose random unvisited neighbour of a cell. The first idea was just to enumerate neighbours such as left = 0, top = 1, right = 2, bottom = 3 and use rand() % 4 to generate random number and choose appropriate cell. However, not all cells features 4 neighbours, so that I had to write following code:
Cell* getRandomNeighbour(const Maze* const maze, const Cell* const currentCell) {
int randomNumb = rand() % 4;
int timer = 1;
while(timer > 0) {
if (randomNumb == 0 && currentCell->x < maze->width-1 && maze->map[currentCell->y][currentCell->x+1].isUnvisited)
return &maze->map[currentCell->y][currentCell->x+1];
if (randomNumb == 1 && currentCell->x > 0 && maze->map[currentCell->y][currentCell->x-1].isUnvisited)
return &maze->map[currentCell->y][currentCell->x-1];
if (randomNumb == 2 && currentCell->y < maze->height-1 && maze->map[currentCell->y+1][currentCell->x].isUnvisited)
return &maze->map[currentCell->y+1][currentCell->x];
if (randomNumb == 3 && currentCell->y > 0 && maze->map[currentCell->y-1][currentCell->x].isUnvisited)
return &maze->map[currentCell->y-1][currentCell->x];
timer--;
randomNumb = rand() % 4;
}
if (currentCell->x < maze->width-1 && maze->map[currentCell->y][currentCell->x+1].isUnvisited)
return &maze->map[currentCell->y][currentCell->x+1];
if (currentCell->x > 0 && maze->map[currentCell->y][currentCell->x-1].isUnvisited)
return &maze->map[currentCell->y][currentCell->x-1];
if (currentCell->y < maze->height-1 && maze->map[currentCell->y+1][currentCell->x].isUnvisited)
return &maze->map[currentCell->y+1][currentCell->x];
if (currentCell->y > 0 && maze->map[currentCell->y-1][currentCell->x].isUnvisited)
return &maze->map[currentCell->y-1][currentCell->x];
return NULL;
}
So, if after 10 iterations the right decision isn't chosen, it will be picked by brute force. This approach seems to be good for the reason that varying of variable timer changes the complexity of maze: the less timer is, the more straightforward maze is. Nevertheless, if my only purpose is to generate completely random maze, it takes a lot of execution time and look a little bit ugly. Is there any pattern(in C language) or way of refactoring that could enable me to deal with this situation without long switches and a lot of if-else constructions?
As #pat and #Ivan Gritsenko suggested, you can limit your random choice to the valid cells only, like this:
Cell* getRandomNeighbour(const Maze* const maze, const Cell* const currentCell)
{
Cell *neighbours[4] = {NULL};
int count = 0;
// first select the valid neighbours
if ( currentCell->x < maze->width - 1
&& maze->map[currentCell->y][currentCell->x + 1].isUnvisited ) {
neighbours[count++] = &maze->map[currentCell->y][currentCell->x + 1];
}
if ( currentCell->x > 0
&& maze->map[currentCell->y][currentCell->x - 1].isUnvisited ) {
neighbours[count++] = &maze->map[currentCell->y][currentCell->x - 1];
}
if ( currentCell->y < maze->height - 1
&& maze->map[currentCell->y + 1][currentCell->x].isUnvisited ) {
neighbours[count++] = &maze->map[currentCell->y + 1][currentCell->x];
}
if ( currentCell->y > 0
&& maze->map[currentCell->y - 1][currentCell->x].isUnvisited ) {
neighbours[count++] = &maze->map[currentCell->y - 1][currentCell->x];
}
// then choose one of them (if any)
int chosen = 0;
if ( count > 1 )
{
int divisor = RAND_MAX / count;
do {
chosen = rand() / divisor;
} while (chosen >= count);
}
return neighbours[chosen];
}
The rationale behind the random number generation part (as opposed to the more common rand() % count) is well explained in this answer.
Factoring repeated code, and a more disciplined way of picking the order of directions to try yields this:
// in_maze returns whether x, y is a valid maze coodinate.
int in_maze(const Maze* const maze, int x, int y) {
return 0 <= x && x < maze->width && 0 <= y && y < maze->height;
}
Cell *get_random_neighbour(const Maze* const maze, const Cell* const c) {
int dirs[] = {0, 1, 2, 3};
// Randomly shuffle dirs.
for (int i = 0; i < 4; i++) {
int r = i + rand() % (4 - i);
int t = dirs[i];
dirs[i] = dirs[r];
dirs[r] = t;
}
// Iterate through the shuffled dirs, returning the first one that's valid.
for (int trial=0; trial<4; trial++) {
int dx = (dirs[trial] == 0) - (dirs[trial] == 2);
int dy = (dirs[trial] == 1) - (dirs[trial] == 3);
if (in_maze(maze, c->x + dx, c->y + dy)) {
const Cell * const ret = &maze->map[c->y + dy][c->x + dx];
if (ret->isUnvisited) return ret;
}
}
return NULL;
}
(Disclaimer: untested -- it probably has a few minor issues, for example const correctness).

Check whether the polygon is convex

I need to check whether the polygon is convex
I know that there were questions here about it, but I need to check the code, whether it is right
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int check_figure(float* x_points[], float* y_points[]);
int main(void) {
int n;
scanf("%i", &n);
int i = 0;
float **x_points = NULL, **y_points = NULL;
x_points = (float**) malloc(sizeof(float*) * (n + 1));
if (x_points == NULL) {
return 0;
}
y_points = (float**) malloc(sizeof(float*) * (n + 1));
if (y_points == NULL) {
return 0;
}
for (i = 0; i < n; i++) {
x_points[i] = (float*) malloc((n + 1) * sizeof(float));
scanf("%f", x_points[i]);
y_points[i] = (float*) malloc((n + 1) * sizeof(float));
scanf("%f", y_points[i]);
}
for (i = 0; i < n - 1; i++) {
if ((x_points[i] == NULL) || (y_points[i] == NULL)) {
return 0;
}
}
x_points[n] = NULL;
y_points[n] = NULL;
int convex = check_figure(x_points, y_points);
if (convex == 1) {
printf("%s", "true");
} else {
printf("%s", "false");
}
free(x_points);
free(y_points);
//free(convex);
return 0;
}
int check_figure(float *x_points[], float *y_points[]) {
float first = 0, booll = 1, sign = 0, result = 0;
int i = 0;
//int *convex = (int*)malloc(sizeof(int));
int convex;
while (1) {
if (x_points[i] != NULL) {
i++;
} else {
break;
}
}
first = *x_points[i - 1] * *y_points[0] - *y_points[i - 1] * *x_points[0];
sign = first / fabsf(first);
int k;
for (k = 0; k < i - 2; k++) {
result = *x_points[k] * *y_points[k + 1] - *x_points[k + 1] * *y_points[k];
booll = booll * sign * result / fabsf(result);
if (booll < 0) {
convex = 0;
return convex;
} else {
convex = 1;
return convex;
}
}
}
there is a sample, for example I input 4 and then I input 0,2; 2,-2; 0,0; -2,-2; and it returns me true, but the polygon is not convex...I really can't get it
A polygon is convex if all of its angles are acute, or 180 degrees (well, then it's not an angle, but depending what your doing, sometimes they happen.) So, just make sure all the angles are acute or 180 degrees.
On 2 dimensions this is not that hard, you just make sure your polygons are always wound the same way, then to test an angle between segments ab and bc, you create another vector by rotating vec2(a - b) 90 degrees towards the middle of the polygon (always the same rotation, because it's always wound the same way. A 90 degree rotation here can be accomplished by flipping the x and y values, and then negating one of the values, based on which way you are rotating.) Then, if the dot product of that rotated vector and the the vector of vec2(c-b) is positive, it is acute, if it is negative, it is obtuse, and if it is 0 it is a straight line. In three dimensions it is also not that hard, but you have to rotate along the same plane as the original angle.
Looking at your code I just have no idea how that is suppose to determine whether or not an angle is acute. At some point you need an angle, or a sine of an angle, or a cosine of an angle (obtained in this method via a dot product), or something somehow related to an angle. There are more direct ways to do this also, this is just a relatively performant one.

Using two Arrays in C/Gameboy programming

For a game in Gameboy programming, I am using four arrays called top, oldTop, bottom and oldBottom:
struct Point { int x, y; };
struct Rect { struct Point xx, yy; };
Rect top[size], oldTop[size];
Rect bottom[size], oldBottom[i];
where Rect is a struct made of two Struct Points, the top-left and the bottom right corner points.
The idea of the game is to have random-heighted blocks top-down from the ceiling and bottom-up from the floor.
It is similar to the copter-classic game. In my infinite while loop, I shift all of the rectangles down by one pixel using the following code
while (1)
{
for (int i = 0; i < size; i++)
{
//in Struct Rect, xx is the top-left corner point, and yy is the bottom right
top[i].xx.x--;
top[i].yy.x--;
bottom[i].xx.x--;
bottom[i].yy.x--;
if (top[i].xx.x < 0)
{
top[i].xx.x += 240;
top[i].yy.x += 240;
}
if (bottom[i].xx.x < 0)
{
bottom[i].xx.x += 240;
bottom[i].yy.x += 240;
}
}
for (int i = 0; i < size; i++)
{
drawRect(oldTop[i], colorBlack);
drawRect(oldBottom[i], colorBlack);
}
/*call delay function that wait for Vertical Blank*/
for(int i = 0; i < size; i++)
{
drawRect(top[i], colorGreen);
drawRect(bottom[i], colorGreen);
oldTop[i] = top[i];
oldBottom[i] = bottom[i];
}
}
The drawRect method uses DMA to draw the rectangle.
with this code, the code should display the rectangles like this: (drew this up in paint)
But the result I get is
What is odd is that if I don't draw the bottom row at all, then the top row draws fine. The result only messes up when I draw both. This is really weird because I think that the code should be working fine, and the code is not very complicated. Is there a specific reason this is happening, and is there a way to remedy this?
Thanks.
The code that I use to draw the rectangle looks like this:
void drawRect(int row, int col, int width, int height){
int i;
for (i=0; i<height; i++)
{
DMA[3].src = &color;
DMA[3].dst = videoBuffer + (row+r)*240 + col);
DMA[3].cnt = DMA_ON | DMA_FIXED_SOURCE | width;
}
}
Here's a debugging SSCCE (Short, Self-Contained, Correct Example) based on your code. There are assertions in this code that fire; it runs, but is known not to be correct. I've renamed bottom to btm and oldBottom to oldBtm so that the names are symmetric; it makes the code layout more systematic (but is otherwise immaterial).
#include <assert.h>
#include <stdio.h>
typedef struct Point { int x, y; } Point;
typedef struct Rect { struct Point xx, yy; } Rect;
enum { size = 2 };
typedef enum { colourGreen = 0, colourBlack = 1 } Colour;
/*ARGSUSED*/
static void drawRect(Rect r, Colour c)
{
printf(" (%3d)(%3d)", r.xx.x, r.yy.x);
}
int main(void)
{
Rect top[size], oldTop[size];
Rect btm[size], oldBtm[size];
int counter = 0;
for (int i = 0; i < size; i++)
{
top[i].xx.x = 240 - 4 * i;
top[i].xx.y = 0 + 10 + i;
top[i].yy.x = 240 - 14 * i;
top[i].yy.y = 0 + 20 + i;
btm[i].xx.x = 0 + 72 * i;
btm[i].xx.y = 0 + 10 * i;
btm[i].yy.x = 0 + 12 * i;
btm[i].yy.y = 0 + 20 * i;
oldTop[i] = top[i];
oldBtm[i] = btm[i];
}
while (1)
{
if (counter++ > 480) // Limit amount of output!
break;
for (int i = 0; i < size; i++)
{
//in Struct Rect, xx is the top-left corner point, and yy is the bottom right
top[i].xx.x--;
top[i].yy.x--;
btm[i].xx.x--;
btm[i].yy.x--;
if (top[i].xx.x < 0)
{
top[i].xx.x += 240;
top[i].yy.x += 240;
}
if (btm[i].xx.x < 0)
{
btm[i].xx.x += 240;
btm[i].yy.x += 240;
}
}
for (int i = 0; i < size; i++)
{
assert(top[i].xx.x >= 0 && top[i].yy.x >= 0);
assert(btm[i].xx.x >= 0 && btm[i].yy.x >= 0);
}
for (int i = 0; i < size; i++)
{
drawRect(oldTop[i], colourBlack);
drawRect(oldBtm[i], colourBlack);
}
/*call delay function that wait for Vertical Blank*/
for(int i = 0; i < size; i++)
{
drawRect(top[i], colourGreen);
drawRect(btm[i], colourGreen);
oldTop[i] = top[i];
oldBtm[i] = btm[i];
}
putchar('\n');
}
return(0);
}
As noted in a late comment, one big difference between this and your code is that oldBottom in your code is declared as:
Rect top[size], oldTop[size];
Rect bottom[size], oldBottom[i];
using the size i instead of size. This probably accounts for array overwriting issues you see.
There's a second problem though; the assertions in the loop in the middle fire:
(240)(240) ( 0)( 0) (236)(226) ( 72)( 12) (239)(239) (239)(239) (235)(225) ( 71)( 11)
(239)(239) (239)(239) (235)(225) ( 71)( 11) (238)(238) (238)(238) (234)(224) ( 70)( 10)
(238)(238) (238)(238) (234)(224) ( 70)( 10) (237)(237) (237)(237) (233)(223) ( 69)( 9)
(237)(237) (237)(237) (233)(223) ( 69)( 9) (236)(236) (236)(236) (232)(222) ( 68)( 8)
(236)(236) (236)(236) (232)(222) ( 68)( 8) (235)(235) (235)(235) (231)(221) ( 67)( 7)
(235)(235) (235)(235) (231)(221) ( 67)( 7) (234)(234) (234)(234) (230)(220) ( 66)( 6)
(234)(234) (234)(234) (230)(220) ( 66)( 6) (233)(233) (233)(233) (229)(219) ( 65)( 5)
(233)(233) (233)(233) (229)(219) ( 65)( 5) (232)(232) (232)(232) (228)(218) ( 64)( 4)
(232)(232) (232)(232) (228)(218) ( 64)( 4) (231)(231) (231)(231) (227)(217) ( 63)( 3)
(231)(231) (231)(231) (227)(217) ( 63)( 3) (230)(230) (230)(230) (226)(216) ( 62)( 2)
(230)(230) (230)(230) (226)(216) ( 62)( 2) (229)(229) (229)(229) (225)(215) ( 61)( 1)
(229)(229) (229)(229) (225)(215) ( 61)( 1) (228)(228) (228)(228) (224)(214) ( 60)( 0)
Assertion failed: (btm[i].xx.x >= 0 && btm[i].yy.x >= 0), function main, file video.c, line 63.
I think your 'not negative' checks should be revised to:
if (top[i].xx.x < 0)
top[i].xx.x += 240;
if (top[i].yy.x < 0)
top[i].yy.x += 240;
if (btm[i].xx.x < 0)
btm[i].xx.x += 240;
if (btm[i].yy.x < 0)
btm[i].yy.x += 240;
This stops anything going negative. However, it is perfectly plausible that you should simply be checking on the bottom-right x-coordinate (instead of the top-left coordinate) using the original block. Or the wraparound may need to be more complex altogether. That's for you to decipher. But I think that the odd displays occur because you were providing negative values where you didn't intend to and weren't supposed to.
The key points to note here are:
When you're debugging an algorithm, you don't have to use the normal display mechanisms.
When you're debugging, reduce loop sizes where you can (size == 2).
Printing just the relevant information (here, the x-coordinates) helped reduce the output.
Putting the counter code to limit the amount of output simplifies things.
If things are going wrong, look for patterns in what is going wrong early.
I had various versions of the drawRect() function before I got to the design shown, which works well on a wide screen (eg 120x65) terminal window.

how to find max value with less iterations

I am changing the phase of signal from 0 to 360 by each degree to get max voltage value.Because if i change phase of the signal the voltage also changes.I have the fallowing code to find max value.
void Maxphase(float *max, unsigned int *index)
{
*max = 0.0;
float value;
unsigned int i, data;
for (i=0;i<=360;i++)
{
phaseset(i);
delay_ms(100);
data = readvalue();
value = voltage(mux1);
if(value > *max) //find max value
{
*max = value; //max voltage
*index = i;
}
}
}
from the above code I am getting Max value(voltage) after 38 sec(360*100) because for every read operation my device needs 100ms delay. This is too large, I can't change hardware thus i want to get the max value within 2 to 3 sec by optimizing software.
then I have tried with the fallowing code.
void Maxphase(float *max1, unsigned int *index1)
{
max = 0.0;
float value;
unsigned int i,j,data;
for (i=0;i<=360;i+=10)
{
phaseset(i);
delay_ms(100);
data = readvalue();
value = voltage(mux1);
if(value > max) //find max value
{
max = value; //max voltage
index = i;
}
}
*max1=max;
*index1=index;
for (i=*index1-9;i<=*index1+9;i+=1)
{
j=i;
phaseset(j);
delay_ms(100);
data = readvalue();
value = voltage(mux1);
if(value > *max1) //find max value
{
*max1 = value; //max voltage
*index1 = i;
}
}
}
I have reduced time from 45 sec to 7 sec. i have reduced iterations 360 to 54(54*100). I want to reduce it 7 sec to 2 sec.
Can any one help me with better algorithm that i can get max value from (0 to 360) with in 2 sec.
I have measured the voltage values using scope by changing phase. I have written below how it vary voltage with phase.
Phase (degree) voltage(max)
0 0.9mv
45 9.5mv
90 9.0mv
135 0.9mv
180 292mv
225 601mv
270 555mv
315 230mv
360 0.9mv
I am new to C programming. Can anyone provide sample code for the best algorithm.
Golden section search is probably what you are after. It is effective, but still pretty simple.
If you want something even faster and more sophisticated, you can use Brent's method.
If you can be sure that there is only a single highest point on your 360 degrees you can do a recursive divide and conquer.
You start by looking e.g. at 0, 180, 270. Let's say you find the answer is that 180 + 270 together have the highest value. Than you start by looking in at 210.... Which side is higher? And so on ...
Exploiting the various comments and suggestions here, I present this untested piece of code. I don't know whether this works at all or is an improvement over the existing source, but it was fun to try, anyway:
extern void phaseset(int);
extern void delay_ms(int);
extern float readvalue();
extern float voltage(int);
extern int mux1;
float probe(int phase)
{
float data;
phaseset(phase);
delay_ms(100);
data = readvalue(); /* data is ignored? */
return voltage(mux1); /* mux1? */
}
/* helper routine, find the max in a given range [phase1, phase2] */
void maxphase_aux(int phase1, float vol1, int phase2, float vol2, int *phaseret, float *volret)
{
float xvol1 = 0, xvol2 = 0;
int xphase1 = -1, xphase2 = -1;
/* test the voltage in the middle */
int phasem = abs(phase2 - phase1) / 2;
float volm = probe(phasem);
if (volm > vol1 && volm > vol2) {
/* middle point is the highest so far,
* search left and right for maximum */
*volret = volm;
*phaseret = phasem;
maxphase_aux(phase1, vol1, phasem, volm, &xphase1, &xvol1);
maxphase_aux(phase2, vol2, phasem, volm, &xphase2, &xvol2);
} else if (volm < vol1 && volm > vol2) {
/* vol1 is the highest so far,
* search between volm and vol1 for maximum */
maxphase_aux(phase1, vol1, phasem, volm, &xphase1, &xvol1);
} else if (volm > vol1 && volm < vol2) {
/* vol2 is the highest so far,
* search between volm and vol2 for maximum */
maxphase_aux(phase2, vol2, phasem, volm, &xphase2, &xvol2);
} else {
/* not possible? */
return;
}
if (xvol1 > volm) {
*volret = xvol1;
*phaseret = xphase1;
}
if (xvol2 > volm) {
*volret = xvol2;
*phaseret = xphase2;
}
}
void maxphase(int *phaseret, float *volret)
{
float v0 = probe(0);
float v360 = probe(360);
maxphase_aux(0, v0, 360, v360, phaseret, volret);
}
UPDATE: 2012-11-10.
#include <stdio.h>
#include <string.h>
#include <math.h>
#define FAKE_TARGET 89
unsigned fake_target = FAKE_TARGET;
float probe_one(unsigned int phase);
void Maxphase(float *max, unsigned int *index);
void Maxphase(float *max, unsigned int *index)
{
unsigned int aim, idx, victim;
struct best {
unsigned pos;
float val;
} samples[4] = {{0, 0.0}, };
for (aim = 0;aim < 360;aim += 90) {
idx=aim/90;
samples[idx].pos = aim;
samples[idx].val = probe_one(samples[idx].pos);
if (!idx || samples[idx].val < samples[victim].val ) victim = idx;
}
/* eliminate the weakist postion, and rotate the rest,
** such that:
** samples[0] := lower boundary.
** samples[1] := our best guess
** samples[2] := upper boundary
** samples[3] := scratch/probe element
*/
fprintf(stderr, "Victim=%u\n", victim );
switch(victim) {
case 0: samples[0] = samples[1]; samples[1] = samples[2]; samples[2] = samples[3]; break;
case 1: samples[1] = samples[3]; samples[3] = samples[0]; samples[0] = samples[2]; samples[2] = samples[3]; break;
case 2: samples[2] = samples[1]; samples[1] = samples[0]; samples[0] = samples[3]; break;
case 3: break;
}
/* Calculation is easier if the positions are increasing.
** (We can always perform the modulo 360 if needed)
*/
if (samples[0].pos > samples[1].pos ) samples[1].pos += 360;
if (samples[1].pos > samples[2].pos ) samples[2].pos += 360;
while( 1) {
int step;
step = samples[2].pos - samples[0].pos;
if (step < 3) break;
do {
fprintf(stderr, "\n[%u %u %u] Diff=%d\n"
, samples[0].pos , samples[1].pos , samples[2].pos , step);
if (step > 0) step++; else step--;
step /= 2;
aim = (samples[0].pos + step ) ;
/* avoid hitting the middle cell twice */
if (aim %360 != samples[1].pos %360) break;
step += 1;
aim = (samples[0].pos + step ) ;
if (aim %360 != samples[1].pos %360) break;
step -= 2;
aim = (samples[0].pos + step ) ;
break;
} while(0);
fprintf(stderr, "Step=%d Aim=%u, Idx=%u\n",step, aim,idx );
samples[3].pos = aim;
samples[3].val = probe_one( samples[3].pos );
victim= (samples[3].pos > samples[1].pos ) ? 2 : 0;
if (samples[3].val > samples[1].val) idx= 1; else idx = victim;
fprintf(stderr, "Victim=%u, TargetIdx=%u\n", victim, idx );
/* This should not happen */
if (samples[3].val < samples[victim].val) break;
if (idx != victim) samples[2-victim] = samples[idx];
samples[idx] = samples[3];
}
*max = samples[1].val;
*index = samples[1].pos % 360;
}
float probe_one(unsigned int phase)
{
float value;
#ifdef FAKE_TARGET
int dif;
dif = fake_target-phase;
if (dif < -180) dif = 360+dif;
else if (dif > 180) dif = 360-dif;
/* value = 1.0 / (1 + pow(phase-231, 2)); */
value = 1.0 / (1 + pow(dif, 2));
fprintf(stderr, "Target = %d: Probe(%d:%d) := %f\n", fake_target, phase, dif, value );
sleep (1);
#else
unsigned int data;
phase %= 360;
phaseset(phase);
delay_ms(100);
data = readvalue(); // what is this ?
value = voltage(mux1);
#endif
return value;
}
int main(int argc, char **argv)
{
float value;
unsigned int index;
if (argv[1]) sscanf (argv[1], "%u", &fake_target);
fake_target %= 360;
Maxphase(&value, &index) ;
printf("Phase=%u Max=%f\n", index, value );
return 0;
}

Resources