plan.c
来自「机器人仿真软件」· C语言 代码 · 共 525 行
C
525 行
/************************************************************************** * Desc: Path planning * Author: Andrew Howard * Date: 10 Oct 2002 * CVS: $Id: plan.c,v 1.21 2006/03/28 19:00:15 gerkey Exp $**************************************************************************/#if HAVE_CONFIG_H #include <config.h>#endif// This header MUST come before <openssl/md5.h>#include <sys/types.h>#if HAVE_OPENSSL_MD5_H && HAVE_LIBCRYPTO #include <openssl/md5.h>#endif#include <assert.h>#include <math.h>#include <float.h>#include <stdlib.h>#include <stdio.h>#include <string.h>#include <errno.h>#include <libplayercore/playercommon.h>#include <libplayercore/error.h>#include "plan.h"//#include "heap.h"#if HAVE_OPENSSL_MD5_H && HAVE_LIBCRYPTO// length of the hash, in unsigned ints#define HASH_LEN (MD5_DIGEST_LENGTH / sizeof(unsigned int))#endif// Create a plannerplan_t *plan_alloc(double abs_min_radius, double des_min_radius, double max_radius, double dist_penalty){ plan_t *plan; plan = calloc(1, sizeof(plan_t)); plan->size_x = 0; plan->size_y = 0; plan->scale = 0.0; plan->min_x = 0; plan->min_y = 0; plan->max_x = 0; plan->max_y = 0; plan->abs_min_radius = abs_min_radius; plan->des_min_radius = des_min_radius; plan->max_radius = max_radius; plan->dist_penalty = dist_penalty; plan->queue_start = 0; plan->queue_len = 0; plan->queue_size = 400000; // HACK: FIX plan->queue = calloc(plan->queue_size, sizeof(plan->queue[0])); plan->waypoint_count = 0; plan->waypoint_size = 100; plan->waypoints = calloc(plan->waypoint_size, sizeof(plan->waypoints[0])); return plan;}// Destroy a plannervoid plan_free(plan_t *plan){ if (plan->cells) free(plan->cells); free(plan->queue); free(plan->waypoints); free(plan); return;}// Reset the planvoid plan_reset(plan_t *plan){ int i, j; plan_cell_t *cell; for (j = 0; j < plan->size_y; j++) { for (i = 0; i < plan->size_x; i++) { cell = plan->cells + PLAN_INDEX(plan, i, j); cell->ci = i; cell->cj = j; cell->occ_state = 0; cell->occ_dist = plan->max_radius; cell->plan_cost = 1e12; cell->plan_next = NULL; } } plan->waypoint_count = 0; return;}voidplan_set_bounds(plan_t* plan, int min_x, int min_y, int max_x, int max_y){ assert(min_x < plan->size_x); assert(min_y < plan->size_y); assert(max_x < plan->size_x); assert(max_y < plan->size_y); assert(min_x <= max_x); assert(min_y <= max_y); plan->min_x = min_x; plan->min_y = min_y; plan->max_x = max_x; plan->max_y = max_y;}intplan_check_inbounds(plan_t* plan, double x, double y){ int gx, gy; gx = PLAN_GXWX(plan, x); gy = PLAN_GYWY(plan, y); if((gx >= plan->min_x) && (gx <= plan->max_x) && (gy >= plan->min_y) && (gy <= plan->max_y)) return(1); else return(0);}voidplan_set_bbox(plan_t* plan, double padding, double min_size, double x0, double y0, double x1, double y1){ int gx0, gy0, gx1, gy1; int min_x, min_y, max_x, max_y; int sx, sy; int dx, dy; int gmin_size; int gpadding; gx0 = PLAN_GXWX(plan, x0); gy0 = PLAN_GYWY(plan, y0); gx1 = PLAN_GXWX(plan, x1); gy1 = PLAN_GYWY(plan, y1); // Make a bounding box to include both points. min_x = MIN(gx0, gx1); min_y = MIN(gy0, gy1); max_x = MAX(gx0, gx1); max_y = MAX(gy0, gy1); // Make sure the min_size is achievable gmin_size = (int)ceil(min_size / plan->scale); gmin_size = MIN(gmin_size, MIN(plan->size_x-1, plan->size_y-1)); // Add padding gpadding = (int)ceil(padding / plan->scale); min_x -= gpadding / 2; min_x = MAX(min_x, 0); max_x += gpadding / 2; max_x = MIN(max_x, plan->size_x - 1); min_y -= gpadding / 2; min_y = MAX(min_y, 0); max_y += gpadding / 2; max_y = MIN(max_y, plan->size_y - 1); // Grow the box if necessary to achieve the min_size sx = max_x - min_x; while(sx < gmin_size) { dx = gmin_size - sx; min_x -= (int)ceil(dx / 2.0); max_x += (int)ceil(dx / 2.0); min_x = MAX(min_x, 0); max_x = MIN(max_x, plan->size_x-1); sx = max_x - min_x; } sy = max_y - min_y; while(sy < gmin_size) { dy = gmin_size - sy; min_y -= (int)ceil(dy / 2.0); max_y += (int)ceil(dy / 2.0); min_y = MAX(min_y, 0); max_y = MIN(max_y, plan->size_y-1); sy = max_y - min_y; } plan_set_bounds(plan, min_x, min_y, max_x, max_y);}voidplan_update_cspace_naive(plan_t* plan){ int i, j; int di, dj, dn; double r; plan_cell_t *cell, *ncell; PLAYER_MSG0(2,"Generating C-space...."); dn = (int) ceil(plan->max_radius / plan->scale); for (j = plan->min_y; j <= plan->max_y; j++) { for (i = plan->min_x; i <= plan->max_x; i++) { cell = plan->cells + PLAN_INDEX(plan, i, j); if (cell->occ_state < 0) continue; cell->occ_dist = FLT_MAX; for (dj = -dn; dj <= +dn; dj++) { for (di = -dn; di <= +dn; di++) { if (!PLAN_VALID_BOUNDS(plan, i + di, j + dj)) continue; ncell = plan->cells + PLAN_INDEX(plan, i + di, j + dj); r = plan->scale * sqrt(di * di + dj * dj); if (r < ncell->occ_dist) ncell->occ_dist = r; } } } }}#if 0voidplan_update_cspace_dp(plan_t* plan){ int i, j; int di, dj, dn; double r; plan_cell_t *cell, *ncell; //heap_t* Q; plan_cell_t** Q; int qhead, qtail; PLAYER_MSG0(2,"Generating C-space...."); // We'll look this far away from obstacles when updating cell costs dn = (int) ceil(plan->max_radius / plan->scale); // We'll need space for, at most, dn^2 cells in our queue (which is a // binary heap). //Q = heap_alloc(dn*dn, NULL); Q = (plan_cell_t**)malloc(sizeof(plan_cell_t*)*dn*dn); assert(Q); // Make space for the marks that we'll use. if(plan->marks_size != plan->size_x*plan->size_y) { plan->marks_size = plan->size_x*plan->size_y; plan->marks = (unsigned char*)realloc(plan->marks, sizeof(unsigned char*) * plan->marks_size); } assert(plan->marks); // For each obstacle (or unknown cell), spread a wave out in all // directions, updating occupancy distances (inverse costs) on the way. // Don't ever raise the occupancy distance of a cell. for (j = 0; j < plan->size_y; j++) { for (i = 0; i < plan->size_x; i++) { cell = plan->cells + PLAN_INDEX(plan, i, j); if (cell->occ_state < 0) continue; //cell->occ_dist = plan->max_radius; cell->occ_dist = 0.0; // clear the marks memset(plan->marks,0,sizeof(unsigned char)*plan->size_x*plan->size_y); // Start with the current cell //heap_reset(Q); //heap_insert(Q, cell->occ_dist, cell); qhead = 0; Q[qhead] = cell; qtail = 1; //while(!heap_empty(Q)) while(qtail != qhead) { //ncell = heap_extract_max(Q); ncell = Q[qhead++]; // Mark it, so we don't come back plan->marks[PLAN_INDEX(plan, ncell->ci, ncell->cj)] = 1; // Is this cell an obstacle or unknown cell (and not the initial // cell? If so, don't bother updating its cost here. if((ncell != cell) && (ncell->occ_state >= 0)) continue; // How far are we from the obstacle cell we started with? r = plan->scale * hypot(ncell->ci - cell->ci, ncell->cj - cell->cj); // Are we past the distance at which we care? if(r > plan->max_radius) continue; // Update the occupancy distance if we're closer if(r < ncell->occ_dist) { ncell->occ_dist = r; // Also put its neighbors on the queue for processing for(dj = -1; dj <= 1; dj+= 2) { for(di = -1; di <= 1; di+= 2) { if (!PLAN_VALID(plan, ncell->ci + di, ncell->cj + dj)) continue; // Have we already seen this cell? if(plan->marks[PLAN_INDEX(plan, ncell->ci + di, ncell->cj + dj)]) continue; // Add it to the queue /* heap_insert(Q, ncell->occ_dist, plan->cells + PLAN_INDEX(plan, ncell->ci+di, ncell->cj+dj)); */ Q[qtail++] = plan->cells + PLAN_INDEX(plan, ncell->ci+di, ncell->cj+dj); } } } } } } //heap_free(Q);}#endif// Construct the configuration space from the occupancy grid.// This treats both occupied and unknown cells as bad.// // If cachefile is non-NULL, then we try to read the c-space from that// file. If that fails, then we construct the c-space as per normal and// then write it out to cachefile.void plan_update_cspace(plan_t *plan, const char* cachefile){#if HAVE_OPENSSL_MD5_H && HAVE_LIBCRYPTO unsigned int hash[HASH_LEN]; plan_md5(hash, plan); if(cachefile && strlen(cachefile)) { PLAYER_MSG1(2,"Trying to read c-space from file %s", cachefile); if(plan_read_cspace(plan,cachefile,hash) == 0) { // Reading from the cache file worked; we're done here. PLAYER_MSG1(2,"Successfully read c-space from file %s", cachefile); return; } PLAYER_MSG1(2, "Failed to read c-space from file %s", cachefile); }#endif //plan_update_cspace_dp(plan); plan_update_cspace_naive(plan);#if HAVE_OPENSSL_MD5_H && HAVE_LIBCRYPTO if(cachefile) plan_write_cspace(plan,cachefile, (unsigned int*)hash);#endif PLAYER_MSG0(2,"Done.");}#if HAVE_OPENSSL_MD5_H && HAVE_LIBCRYPTO// Write the cspace occupancy distance values to a file, one per line.// Read them back in with plan_read_cspace().// Returns non-zero on error.int plan_write_cspace(plan_t *plan, const char* fname, unsigned int* hash){ plan_cell_t* cell; int i,j; FILE* fp; if(!(fp = fopen(fname,"w+"))) { PLAYER_MSG2(2,"Failed to open file %s to write c-space: %s", fname,strerror(errno)); return(-1); } fprintf(fp,"%d\n%d\n", plan->size_x, plan->size_y); fprintf(fp,"%.3lf\n%.3lf\n", plan->origin_x, plan->origin_y); fprintf(fp,"%.3lf\n%.3lf\n", plan->scale,plan->max_radius); for(i=0;i<HASH_LEN;i++) fprintf(fp,"%08X", hash[i]); fprintf(fp,"\n"); for(j = 0; j < plan->size_y; j++) { for(i = 0; i < plan->size_x; i++) { cell = plan->cells + PLAN_INDEX(plan, i, j); fprintf(fp,"%.3f\n", cell->occ_dist); } } fclose(fp); return(0);}// Read the cspace occupancy distance values from a file, one per line.// Write them in first with plan_read_cspace().// Returns non-zero on error.int plan_read_cspace(plan_t *plan, const char* fname, unsigned int* hash){ plan_cell_t* cell; int i,j; FILE* fp; int size_x, size_y; double origin_x, origin_y; double scale, max_radius; unsigned int cached_hash[HASH_LEN]; if(!(fp = fopen(fname,"r"))) { PLAYER_MSG1(2,"Failed to open file %s", fname); return(-1); } /* Read out the metadata */ if((fscanf(fp,"%d", &size_x) < 1) || (fscanf(fp,"%d", &size_y) < 1) || (fscanf(fp,"%lf", &origin_x) < 1) || (fscanf(fp,"%lf", &origin_y) < 1) || (fscanf(fp,"%lf", &scale) < 1) || (fscanf(fp,"%lf", &max_radius) < 1)) { PLAYER_MSG1(2,"Failed to read c-space metadata from file %s", fname); fclose(fp); return(-1); } for(i=0;i<HASH_LEN;i++) { if(fscanf(fp,"%08X", cached_hash+i) < 1) { PLAYER_MSG1(2,"Failed to read c-space metadata from file %s", fname); fclose(fp); return(-1); } } /* Verify that metadata matches */ if((size_x != plan->size_x) || (size_y != plan->size_y) || (fabs(origin_x - plan->origin_x) > 1e-3) || (fabs(origin_y - plan->origin_y) > 1e-3) || (fabs(scale - plan->scale) > 1e-3) || (fabs(max_radius - plan->max_radius) > 1e-3) || memcmp(cached_hash, hash, sizeof(unsigned int) * HASH_LEN)) { PLAYER_MSG1(2,"Mismatch in c-space metadata read from file %s", fname); fclose(fp); return(-1); } for(j = 0; j < plan->size_y; j++) { for(i = 0; i < plan->size_x; i++) { cell = plan->cells + PLAN_INDEX(plan, i, j); if(fscanf(fp,"%f", &(cell->occ_dist)) < 1) { PLAYER_MSG3(2,"Failed to read c-space data for cell (%d,%d) from file %s", i,j,fname); fclose(fp); return(-1); } } } fclose(fp); return(0);}// Compute the 16-byte MD5 hash of the map data in the given plan// object.voidplan_md5(unsigned int* digest, plan_t* plan){ MD5_CTX c; MD5_Init(&c); MD5_Update(&c,(const unsigned char*)plan->cells, (plan->size_x*plan->size_y)*sizeof(plan_cell_t)); MD5_Final((unsigned char*)digest,&c);}#endif // HAVE_OPENSSL_MD5_H && HAVE_LIBCRYPTO
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?