#include "motion.h" #include "math/mathutils.h" #include "planner.h" #include #include #include #include #include static bool add_point(MotionPath *path, double input[4], uint32_t time) { if (path->len >= path->cap) { path->cap *= 2; printf("new cap %d\n", path->cap); MotionPoint *tmp = path->points; const size_t psize = sizeof(MotionPoint) * path->cap; path->points = malloc(psize); memset(path->points, 0, psize); memcpy(path->points, tmp, sizeof(MotionPoint) * (path->len)); free(tmp); if (path->points == NULL) { printf("reallocation failed in add_point\n"); free(path->points); return false; } } path->points[path->len++] = (MotionPoint) { .leftx = input[0], .lefty = input[1], .rightx = input[2], .righty = input[3], .time = time, }; return true; } MotionPath load_path(const char *filename, Field *field) { FILE *file; fopen_s(&file, filename, "r"); const int filename_len = strlen(filename) + 1; const size_t psize = sizeof(MotionPoint) * PATH_INIT_SIZE; MotionPath path = { .name = malloc(sizeof(char) * filename_len), .points = malloc(psize), .cap = PATH_INIT_SIZE, .len = 0, .odo_path = NULL, .bounding_box = { 0, 0, 0, 0 }, }; strcpy_s(path.name, filename_len, filename); memset(path.points, 0, psize); char num_buf[200]; int num_top = 0; double point_data[4]; int point_top = 0; char ch; while ((ch = fgetc(file)) != EOF) { switch (ch) { case '-': case '.': case '0' ... '9': num_buf[num_top++] = ch; break; case ',': num_buf[num_top++] = '\0'; point_data[point_top++] = atof(num_buf); num_top = 0; break; case '\n': num_buf[num_top++] = '\0'; add_point(&path, point_data, atoi(num_buf)); num_top = 0; point_top = 0; break; default: break; } } fclose(file); build_odo_mpath(&path, field); return path; } // PERF: you know your data is well structured // when serialization is this easy void save_path(MotionPath *path) { FILE *file; fopen_s(&file, path->name, "w+"); for (int i = 0; i < path->len; i++) { fprintf(file, "%f,%f,%f,%f,%d\n", path->points[i].leftx, path->points[i].lefty, path->points[i].rightx, path->points[i].righty, path->points[i].time); } fclose(file); printf("saved motion path %s\n", path->name); } bool free_path(MotionPath *path) { if (path == NULL) return false; free(path->name); free(path->points); path->name = NULL; path->points = NULL; return true; } static inline double motion_curve(double i) { return i; } void build_odo_mpath(MotionPath *path, Field *field) { if (path->odo_path != NULL) return; const size_t path_size = sizeof(point) * path->len; path->odo_path = malloc(path_size); memset(path->odo_path, 0, path_size); printf("building odo mpath\n"); double x = field->startx; double y = field->starty; path->odo_path[0] = (point) { .x = field->startx, .y = field->starty, }; for (int i = 1; i < path->len; i++) { // get the inputs (should represent the derivative of our auto) double ix = path->points[i].leftx; double iy = path->points[i].lefty; // multiply by speed double dx = iy * field->xy_speed; double dy = ix * field->xy_speed; // take the time difference (in seconds) and multiply the derivative by it dx *= (path->points[i].time - path->points[i-1].time) / 1000.f; dy *= (path->points[i].time - path->points[i-1].time) / 1000.f; /* overall, for the x axis the full equation should look like this: * (leftx_input * speed) * ((time_ms1 - time_ms0) / 1000) * * a few other useful facts: * input * speed = distance * */ path->odo_path[i] = (point) {x, y}; // change x & y by the derivative x += dx; y += dy; } printf("built odo mpath\n"); }