00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <errno.h>
00023 #include <signal.h>
00024 #include <stdio.h>
00025 #include <string.h>
00026 #include <sys/resource.h>
00027 #include <sys/time.h>
00028 #include <sys/types.h>
00029 #include <unistd.h>
00030
00031 #include <pthread.h>
00032
00033
00034
00035 #include <igh_eml/ecrt.h>
00036
00037
00038
00039 #include "realtime.h"
00040
00041
00042
00043 #define FREQUENCY 1000
00044
00045
00046 #define CONFIGURE_PDOS 1
00047 #define EXTERNAL_MEMORY 1
00048 #define SDO_ACCESS 0
00049
00050
00051
00052 static ec_master_t *master = NULL;
00053 static ec_master_state_t master_state;
00054
00055 static ec_domain_t *domain1 = NULL;
00056 static ec_domain_state_t domain1_state;
00057
00058 static ec_slave_config_t *sc[4];
00059 static ec_slave_config_state_t sc_state[4];
00060
00061 static char prevent_set_position = 0;
00062
00063 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
00064 static int exiting = 0;
00065 static pthread_t thread;
00066 static int misses=0;
00067
00068
00069
00070
00071 static uint8_t *domain1_pd;
00072
00073
00074 #define M0SlavePos 0, 0
00075 #define M1SlavePos 0, 1
00076 #define M2SlavePos 0, 2
00077 #define M3SlavePos 0, 3
00078
00079
00080 #define BM3411 0x0000015a, 0x03010001
00081
00082
00083
00084 static unsigned int off_target_velocity[4];
00085
00086
00087 static unsigned int off_statusword[4];
00088 static unsigned int off_speed_ctrlr_output[4];
00089 static unsigned int off_actual_position[4];
00090 static unsigned int off_actual_velocity[4];
00091
00092 static unsigned int off_torque_actual_value[4];
00093 static unsigned int off_torque_add_value[4];
00094 static unsigned int off_target_position[4];
00095 static unsigned int off_pos_ctrlr_output[4];
00096
00097
00098 static const ec_pdo_entry_reg_t domain1_regs[] = {
00099
00100 {M0SlavePos, BM3411, 0x4169, 0, &off_target_position[0], 0},
00101 {M1SlavePos, BM3411, 0x4169, 0, &off_target_position[1], 0},
00102 {M2SlavePos, BM3411, 0x4169, 0, &off_target_position[2], 0},
00103 {M3SlavePos, BM3411, 0x4169, 0, &off_target_position[3], 0},
00104
00105 {M0SlavePos, BM3411, 0x6042, 0, &off_target_velocity[0], 0},
00106 {M1SlavePos, BM3411, 0x6042, 0, &off_target_velocity[1], 0},
00107 {M2SlavePos, BM3411, 0x6042, 0, &off_target_velocity[2], 0},
00108 {M3SlavePos, BM3411, 0x6042, 0, &off_target_velocity[3], 0},
00109
00110
00111 {M0SlavePos, BM3411, 0x43fe, 0, &off_torque_add_value[0], 0},
00112 {M1SlavePos, BM3411, 0x43fe, 0, &off_torque_add_value[1], 0},
00113 {M2SlavePos, BM3411, 0x43fe, 0, &off_torque_add_value[2], 0},
00114 {M3SlavePos, BM3411, 0x43fe, 0, &off_torque_add_value[3], 0},
00115
00116
00117
00118 {M0SlavePos, BM3411, 0x6041, 0, &off_statusword[0], 0},
00119 {M1SlavePos, BM3411, 0x6041, 0, &off_statusword[1], 0},
00120 {M2SlavePos, BM3411, 0x6041, 0, &off_statusword[2], 0},
00121 {M3SlavePos, BM3411, 0x6041, 0, &off_statusword[3], 0},
00122
00123
00124 {M0SlavePos, BM3411, 0x415F, 0, &off_pos_ctrlr_output[0], 0},
00125 {M1SlavePos, BM3411, 0x415F, 0, &off_pos_ctrlr_output[1], 0},
00126 {M2SlavePos, BM3411, 0x415F, 0, &off_pos_ctrlr_output[2], 0},
00127 {M3SlavePos, BM3411, 0x415F, 0, &off_pos_ctrlr_output[3], 0},
00128
00129
00130 {M0SlavePos, BM3411, 0x416a, 0, &off_actual_position[0], 0},
00131 {M1SlavePos, BM3411, 0x416a, 0, &off_actual_position[1], 0},
00132 {M2SlavePos, BM3411, 0x416a, 0, &off_actual_position[2], 0},
00133 {M3SlavePos, BM3411, 0x416a, 0, &off_actual_position[3], 0},
00134
00135
00136 {M0SlavePos, BM3411, 0x606c, 0, &off_actual_velocity[0], 0},
00137 {M1SlavePos, BM3411, 0x606c, 0, &off_actual_velocity[1], 0},
00138 {M2SlavePos, BM3411, 0x606c, 0, &off_actual_velocity[2], 0},
00139 {M3SlavePos, BM3411, 0x606c, 0, &off_actual_velocity[3], 0},
00140
00141
00142 {M0SlavePos, BM3411, 0x414d, 0, &off_torque_actual_value[0], 0},
00143 {M1SlavePos, BM3411, 0x414d, 0, &off_torque_actual_value[1], 0},
00144 {M2SlavePos, BM3411, 0x414d, 0, &off_torque_actual_value[2], 0},
00145 {M3SlavePos, BM3411, 0x414d, 0, &off_torque_actual_value[3], 0},
00146
00147 {0,0, 0,0, 0, 0, 0, 0}
00148 };
00149
00150 static unsigned int counter = 0;
00151
00152 static int max_v = 100;
00153
00154 static omniwrite_t tar, tar_buffer;
00155 static omniread_t cur, cur_buffer;
00156
00157
00158
00159
00160 static ec_pdo_entry_info_t foo_pdo_entries[] = {
00161
00162
00163 {0x4169, 0, 32},
00164 {0x6042, 0, 16},
00165 {0x43fe, 0, 16},
00166
00167
00168 {0x6041, 0, 16},
00169 {0x415F, 0, 16},
00170 {0x416a, 0, 32},
00171 {0x606c, 0, 32},
00172 {0x414d, 0, 16},
00173 };
00174
00175
00176 static ec_pdo_info_t foo_pdos[] = {
00177 {0x1600, 3, foo_pdo_entries},
00178 {0x1a00, 5, foo_pdo_entries + 3},
00179 };
00180
00181
00182 static ec_sync_info_t foo_syncs[] = {
00183 {2 , EC_DIR_OUTPUT, 1, foo_pdos, EC_WD_DISABLE},
00184 {3 , EC_DIR_INPUT, 1, foo_pdos + 1, EC_WD_DISABLE},
00185 {0xff , 0, 0, 0, EC_WD_DISABLE}
00186 };
00187
00188
00189
00190
00191
00192 void check_domain1_state(void)
00193 {
00194 ec_domain_state_t ds;
00195
00196 ecrt_domain_state(domain1, &ds);
00197
00198 if (ds.working_counter != domain1_state.working_counter)
00199 printf("Domain1: WC %u.\n", ds.working_counter);
00200 if (ds.wc_state != domain1_state.wc_state)
00201 printf("Domain1: State %u.\n", ds.wc_state);
00202
00203 domain1_state = ds;
00204 cur.working_counter = ds.working_counter;
00205 cur.working_counter_state = ds.wc_state;
00206 }
00207
00208
00209
00210
00211
00212 void check_master_state(void)
00213 {
00214 ec_master_state_t ms;
00215
00216 ecrt_master_state(master, &ms);
00217
00218 if (ms.slaves_responding != master_state.slaves_responding)
00219 printf("%u slave(s).\n", ms.slaves_responding);
00220 if (ms.al_states != master_state.al_states)
00221 printf("AL states: 0x%02X.\n", ms.al_states);
00222 if (ms.link_up != master_state.link_up)
00223 printf("Link is %s.\n",
00224 ms.link_up ? "up" : "down");
00225
00226 master_state = ms;
00227 cur.master_link = ms.link_up;
00228 cur.master_al_states = ms.al_states;
00229 cur.master_slaves_responding = ms.slaves_responding;
00230
00231 }
00232
00233
00234
00235 void check_slave_config_states(void)
00236 {
00237 int i;
00238
00239 ec_slave_config_state_t s;
00240
00241 for (i = 0; i < 4; i++) {
00242 ecrt_slave_config_state(sc[i], &s);
00243 if (s.al_state != sc_state[i].al_state)
00244 printf("m%d: State 0x%02X.\n", i, s.al_state);
00245 if (s.online != sc_state[i].online)
00246 printf("m%d: %s.\n", i,
00247 s.online ? "online" : "offline");
00248 if (s.operational != sc_state[i].operational)
00249 printf("m%d: %soperational.\n", i,
00250 s.operational ? "" : "Not ");
00251 sc_state[i] = s;
00252
00253 cur.slave_state[i] = s.al_state;
00254 cur.slave_online[i] = s.online;
00255 cur.slave_operational[i] = s.operational;
00256 }
00257 }
00258
00259
00260
00261
00262 void cyclic_task()
00263 {
00264 int i;
00265
00266
00267 ecrt_master_receive(master);
00268 ecrt_domain_process(domain1);
00269
00270
00271 check_domain1_state();
00272
00273 for (i = 0; i < 4; i++) {
00274 cur.status[i] = EC_READ_U16(domain1_pd + off_statusword[i]);
00275 cur.speed_ctrlr_output[i] = EC_READ_S16(domain1_pd + off_speed_ctrlr_output[i]);
00276 cur.pos_ctrlr_output[i] = EC_READ_S16(domain1_pd + off_pos_ctrlr_output[i]);
00277
00278 cur.position[i] = EC_READ_U32(domain1_pd + off_actual_position[i]);
00279 cur.actual_velocity[i] = EC_READ_S32(domain1_pd + off_actual_velocity[i]);
00280 cur.torque_actual_value[i] = EC_READ_S16(domain1_pd + off_torque_actual_value[i]);
00281 }
00282
00283
00284
00285 if (counter) {
00286 counter--;
00287 } else {
00288 counter = FREQUENCY;
00289
00290
00291 check_master_state();
00292
00293
00294 check_slave_config_states();
00295 }
00296
00297 if(tar.target_position[0] == 0 &&
00298 tar.target_position[1] == 0 &&
00299 tar.target_position[2] == 0 &&
00300 tar.target_position[3] == 0) {
00301 for (i = 0; i < 4; i++) {
00302 EC_WRITE_U32(domain1_pd + off_target_position[i], cur.position[i]);
00303 }
00304 prevent_set_position = 1;
00305 } else {
00306 prevent_set_position = 0;
00307 }
00308
00309
00310
00311 for (i = 0; i < 4; i++) {
00312 if(!prevent_set_position) {
00313 EC_WRITE_U32(domain1_pd + off_target_position[i], tar.target_position[i]);
00314 }
00315 EC_WRITE_S16(domain1_pd + off_torque_add_value[i], tar.torque_add_set_value[i]);
00316 EC_WRITE_S16(domain1_pd + off_target_velocity[i], tar.target_velocity[i]);
00317 }
00318
00319
00320 ecrt_domain_queue(domain1);
00321 ecrt_master_send(master);
00322
00323 cur.pkg_count = counter;
00324
00325 }
00326
00327
00328
00329
00330
00331 static void enforce_max_velocities(omniwrite_t *t)
00332 {
00333 int i;
00334
00335 for (i = 0; i < 4; i++) {
00336 t->target_velocity[i] =
00337 (t->target_velocity[i] > max_v) ? max_v : t->target_velocity[i];
00338 t->target_velocity[i] =
00339 (t->target_velocity[i] < -max_v) ? -max_v : t->target_velocity[i];
00340 }
00341 }
00342
00343
00344
00345
00346 static void stop_motors(void)
00347 {
00348 int i;
00349
00350 for (i = 0; i < 4; i++)
00351 EC_WRITE_S16(domain1_pd + off_target_velocity[i], 0);
00352
00353
00354 ecrt_domain_queue(domain1);
00355 ecrt_master_send(master);
00356
00357
00358 }
00359
00360
00361 static void timespecInc(struct timespec *tick, int nsec)
00362 {
00363 tick->tv_nsec += nsec;
00364 while (tick->tv_nsec >= 1e9)
00365 {
00366 tick->tv_nsec -= 1e9;
00367 tick->tv_sec++;
00368 }
00369 }
00370
00371
00372 void* realtimeMain(void* udata)
00373 {
00374 struct timespec tick;
00375 int period = 1e+6;
00376
00377 while(!exiting)
00378 {
00379 cyclic_task();
00380
00381 if(pthread_mutex_trylock(&mutex) == 0)
00382 {
00383 tar = tar_buffer;
00384 cur_buffer = cur;
00385 pthread_mutex_unlock(&mutex);
00386 }
00387
00388
00389 timespecInc(&tick, period);
00390
00391 struct timespec before;
00392 clock_gettime(CLOCK_REALTIME, &before);
00393 if ((before.tv_sec + before.tv_nsec/1e9) > (tick.tv_sec + tick.tv_nsec/1e9))
00394 {
00395
00396 tick.tv_sec = before.tv_sec;
00397 tick.tv_nsec = (before.tv_nsec / period) * period;
00398 timespecInc(&tick, period);
00399
00400 misses++;
00401 }
00402
00403 clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &tick, NULL);
00404
00405 }
00406
00407 stop_motors();
00408
00409
00410 printf("Releasing master...\n");
00411 ecrt_release_master(master);
00412
00413 return 0;
00414 }
00415
00416
00417
00418
00419
00420
00421 int start_omni_realtime(int max_vel)
00422 {
00423 int i;
00424
00425 max_v = max_vel;
00426
00427 printf("Init omni...\n");
00428
00429
00430 memset(&tar, 0, sizeof(tar));
00431 memset(&cur, 0, sizeof(cur));
00432 cur.magic_version = OMNICOM_MAGIC_VERSION;
00433
00434 printf("Starting omni....\n");
00435
00436 if (!(master = ecrt_request_master(0))) {
00437 printf( "Requesting master 0 failed!\n");
00438 goto out_return;
00439 }
00440
00441 printf("Registering domain...\n");
00442 if (!(domain1 = ecrt_master_create_domain(master))) {
00443 printf( "Domain creation failed!\n");
00444 goto out_release_master;
00445 }
00446
00447 for (i = 0; i < 4; i++) {
00448
00449 if (!(sc[i] = ecrt_master_slave_config(master, 0, i , BM3411))) {
00450 printf(
00451 "Failed to get slave configuration for motor %d.\n", i);
00452 goto out_release_master;
00453 }
00454 printf("Configuring PDOs for motor %d...\n", i);
00455
00456 if (ecrt_slave_config_pdos(sc[i], EC_END, foo_syncs)) {
00457 printf( "Failed to configure PDOs for motor %d.\n", i);
00458 goto out_release_master;
00459 }
00460 }
00461
00462 printf("Registering PDO entries...\n");
00463 if (ecrt_domain_reg_pdo_entry_list(domain1, domain1_regs)) {
00464 printf( "PDO entry registration failed!\n");
00465 goto out_release_master;
00466 }
00467
00468 printf("Activating master...\n");
00469 if (ecrt_master_activate(master)) {
00470 printf( "Failed to activate master!\n");
00471 goto out_release_master;
00472 }
00473
00474 domain1_pd = ecrt_domain_data(domain1);
00475
00476 printf("Starting cyclic thread.\n");
00477
00478 pthread_attr_t tattr;
00479 struct sched_param sparam;
00480 sparam.sched_priority = sched_get_priority_max(SCHED_FIFO);
00481 pthread_attr_init(&tattr);
00482 pthread_attr_setschedpolicy(&tattr, SCHED_FIFO);
00483 pthread_attr_setschedparam(&tattr, &sparam);
00484 pthread_attr_setinheritsched (&tattr, PTHREAD_EXPLICIT_SCHED);
00485
00486 if(pthread_create(&thread, &tattr, &realtimeMain, 0) != 0) {
00487 printf("# ERROR: could not create realtime thread\n");
00488 goto out_release_master;
00489 }
00490
00491
00492 printf("Started.\n");
00493
00494 return 1;
00495
00496 out_release_master:
00497 printf( "Releasing master...\n");
00498 ecrt_release_master(master);
00499 out_return:
00500 printf( "Failed to load. Aborting.\n");
00501 return 0;
00502 }
00503
00504
00505
00506 void stop_omni_realtime(void)
00507 {
00508 printf("Stopping...\n");
00509
00510
00511
00512 exiting = 1;
00513 pthread_join(thread, 0);
00514
00515
00516
00517
00518
00519
00520 printf("Unloading.\n");
00521 }
00522
00523
00524 void omni_write_data(struct omniwrite data)
00525 {
00526 pthread_mutex_lock(&mutex);
00527 tar_buffer = data;
00528 enforce_max_velocities(&tar_buffer);
00529 pthread_mutex_unlock(&mutex);
00530 }
00531
00532 struct omniread omni_read_data()
00533 {
00534 struct omniread data;
00535 pthread_mutex_lock(&mutex);
00536 data = cur_buffer;
00537 pthread_mutex_unlock(&mutex);
00538 return data;
00539 }