/src/Controller/api/skin.c

https://github.com/cyberbotics/webots · C · 308 lines · 258 code · 27 blank · 23 comment · 45 complexity · 4315d6969c4788bdb0b71905ea4efff9 MD5 · raw file

  1. /*
  2. * Copyright 1996-2020 Cyberbotics Ltd.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include <webots/nodes.h>
  17. #include <webots/robot.h>
  18. #include <webots/skin.h>
  19. #include <webots/types.h>
  20. #include "device_private.h"
  21. #include "messages.h"
  22. #include "robot_private.h"
  23. #include <assert.h>
  24. #include <math.h>
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. typedef struct BoneRequest {
  28. int type;
  29. int bone_index;
  30. double values[4];
  31. bool absolute;
  32. struct BoneRequest *next;
  33. } BoneRequest;
  34. typedef struct {
  35. BoneRequest *root_request;
  36. BoneRequest *last_request;
  37. int bone_count;
  38. char **bone_names;
  39. double *bone_position;
  40. double *bone_orientation;
  41. } Skin;
  42. static Skin *skin_create() {
  43. Skin *skin = malloc(sizeof(Skin));
  44. skin->root_request = NULL;
  45. skin->last_request = NULL;
  46. skin->bone_count = 0;
  47. skin->bone_position = malloc(3 * sizeof(double));
  48. skin->bone_orientation = malloc(4 * sizeof(double));
  49. return skin;
  50. }
  51. static Skin *skin_get_struct(WbDeviceTag t) {
  52. WbDevice *d = robot_get_device_with_node(t, WB_NODE_SKIN, true);
  53. return d ? d->pdata : NULL;
  54. }
  55. static void skin_read_answer(WbDevice *d, WbRequest *r) {
  56. int bone_count;
  57. Skin *skin = (Skin *)d->pdata;
  58. switch (request_read_uchar(r)) {
  59. case C_CONFIGURE:
  60. bone_count = request_read_uint32(r);
  61. skin->bone_count = bone_count;
  62. skin->bone_names = malloc((bone_count) * sizeof(char *));
  63. int i = 0;
  64. for (i = 0; i < bone_count; ++i)
  65. skin->bone_names[i] = request_read_string(r);
  66. break;
  67. case C_SKIN_GET_BONE_POSITION:
  68. skin->bone_position[0] = request_read_double(r);
  69. skin->bone_position[1] = request_read_double(r);
  70. skin->bone_position[2] = request_read_double(r);
  71. break;
  72. case C_SKIN_GET_BONE_ORIENTATION:
  73. skin->bone_orientation[0] = request_read_double(r);
  74. skin->bone_orientation[1] = request_read_double(r);
  75. skin->bone_orientation[2] = request_read_double(r);
  76. skin->bone_orientation[3] = request_read_double(r);
  77. break;
  78. default:
  79. ROBOT_ASSERT(0);
  80. break;
  81. }
  82. }
  83. static void skin_write_request(WbDevice *d, WbRequest *r) {
  84. Skin *skin = (Skin *)d->pdata;
  85. BoneRequest *request = skin->root_request;
  86. while (request != NULL) {
  87. request_write_uchar(r, request->type);
  88. request_write_uint16(r, (unsigned short int)(request->bone_index));
  89. if (request->type == C_SKIN_SET_BONE_ORIENTATION || request->type == C_SKIN_SET_BONE_POSITION) {
  90. request_write_double(r, request->values[0]);
  91. request_write_double(r, request->values[1]);
  92. request_write_double(r, request->values[2]);
  93. if (request->type == C_SKIN_SET_BONE_ORIENTATION)
  94. request_write_double(r, request->values[3]); // angle
  95. }
  96. request_write_uchar(r, request->absolute);
  97. BoneRequest *previous = request;
  98. request = request->next;
  99. free(previous);
  100. }
  101. skin->last_request = NULL;
  102. skin->root_request = NULL;
  103. }
  104. static void skin_cleanup(WbDevice *d) {
  105. Skin *skin = (Skin *)d->pdata;
  106. if (skin == NULL)
  107. return;
  108. BoneRequest *request = skin->root_request;
  109. while (request != NULL) {
  110. BoneRequest *previous = request;
  111. request = request->next;
  112. free(previous);
  113. }
  114. skin->root_request = NULL;
  115. skin->last_request = NULL;
  116. int i;
  117. for (i = 0; i < skin->bone_count; ++i)
  118. free(skin->bone_names[i]);
  119. free(skin->bone_names);
  120. free(skin->bone_position);
  121. free(skin->bone_orientation);
  122. free(skin);
  123. d->pdata = NULL;
  124. }
  125. static void add_request(Skin *skin, BoneRequest *request) {
  126. if (skin->root_request == NULL)
  127. skin->root_request = request;
  128. if (skin->last_request != NULL)
  129. skin->last_request->next = request;
  130. skin->last_request = request;
  131. }
  132. // Protected functions (exported to WbDevice.cc)
  133. void wb_skin_init(WbDevice *d) {
  134. d->pdata = skin_create();
  135. d->write_request = skin_write_request;
  136. d->read_answer = skin_read_answer;
  137. d->cleanup = skin_cleanup;
  138. }
  139. // Public functions available from the user API
  140. void wb_skin_set_bone_orientation(WbDeviceTag tag, int index, const double orientation[4], bool absolute) {
  141. int i;
  142. for (i = 0; i < 4; i++) {
  143. if (isnan(orientation[i])) {
  144. fprintf(stderr, "Error: %s() called with a NaN orientation value.\n", __FUNCTION__);
  145. return;
  146. }
  147. }
  148. // Check if axis is valid
  149. if ((orientation[0] == 0.0 && orientation[1] == 0.0 && orientation[2] == 0.0)) {
  150. fprintf(stderr, "Error: %s() called with invalid values for the [x y z] orientation axis.\n", __FUNCTION__);
  151. return;
  152. }
  153. robot_mutex_lock_step();
  154. Skin *skin = skin_get_struct(tag);
  155. // Check if joint index is valid
  156. if (skin) {
  157. if (index < 0 || index >= skin->bone_count) {
  158. fprintf(stderr, "Error: The index of %s() is out of the bounds.\n", __FUNCTION__);
  159. robot_mutex_unlock_step();
  160. return;
  161. }
  162. BoneRequest *request = malloc(sizeof(BoneRequest));
  163. request->type = C_SKIN_SET_BONE_ORIENTATION;
  164. request->bone_index = index;
  165. request->values[0] = orientation[0];
  166. request->values[1] = orientation[1];
  167. request->values[2] = orientation[2];
  168. request->values[3] = orientation[3];
  169. request->absolute = absolute;
  170. request->next = NULL;
  171. add_request(skin, request);
  172. } else
  173. fprintf(stderr, "Error: %s(): invalid device tag.\n", __FUNCTION__);
  174. wb_robot_flush_unlocked();
  175. robot_mutex_unlock_step();
  176. }
  177. void wb_skin_set_bone_position(WbDeviceTag tag, int index, const double position[3], bool absolute) {
  178. int i;
  179. for (i = 0; i < 3; i++) {
  180. if (isnan(position[i])) {
  181. fprintf(stderr, "Error: %s() called with a NaN value.\n", __FUNCTION__);
  182. return;
  183. }
  184. }
  185. robot_mutex_lock_step();
  186. Skin *skin = skin_get_struct(tag);
  187. // Check if joint index is valid
  188. if (skin) {
  189. if (index < 0 || index >= skin->bone_count) {
  190. fprintf(stderr, "Error: The index of %s() is out of the bounds.\n", __FUNCTION__);
  191. robot_mutex_unlock_step();
  192. return;
  193. }
  194. BoneRequest *request = malloc(sizeof(BoneRequest));
  195. request->type = C_SKIN_SET_BONE_POSITION;
  196. request->bone_index = index;
  197. request->values[0] = position[0];
  198. request->values[1] = position[1];
  199. request->values[2] = position[2];
  200. request->absolute = absolute;
  201. request->next = NULL;
  202. add_request(skin, request);
  203. } else
  204. fprintf(stderr, "Error: %s(): invalid device tag.\n", __FUNCTION__);
  205. wb_robot_flush_unlocked();
  206. robot_mutex_unlock_step();
  207. }
  208. int wb_skin_get_bone_count(WbDeviceTag tag) {
  209. int result = 0;
  210. robot_mutex_lock_step();
  211. Skin *skin = skin_get_struct(tag);
  212. if (skin)
  213. result = skin->bone_count;
  214. else
  215. fprintf(stderr, "Error: %s(): invalid device tag.\n", __FUNCTION__);
  216. robot_mutex_unlock_step();
  217. return result;
  218. }
  219. const char *wb_skin_get_bone_name(WbDeviceTag tag, int index) {
  220. char *result = NULL;
  221. robot_mutex_lock_step();
  222. Skin *skin = skin_get_struct(tag);
  223. // Check if joint index is valid
  224. if (skin) {
  225. if (index < 0 || index >= skin->bone_count) {
  226. robot_mutex_unlock_step();
  227. fprintf(stderr, "Error: The index of %s() is out of the bounds.\n", __FUNCTION__);
  228. return result;
  229. }
  230. result = skin->bone_names[index];
  231. } else
  232. fprintf(stderr, "Error: %s(): invalid device tag.\n", __FUNCTION__);
  233. robot_mutex_unlock_step();
  234. return result;
  235. }
  236. const double *wb_skin_get_bone_position(WbDeviceTag tag, int index, bool absolute) {
  237. Skin *skin = skin_get_struct(tag);
  238. if (!skin) {
  239. fprintf(stderr, "Error: %s(): invalid device tag.\n", __FUNCTION__);
  240. return NULL;
  241. }
  242. robot_mutex_lock_step();
  243. // Check if joint index is valid
  244. if (index < 0 || index >= skin->bone_count) {
  245. robot_mutex_unlock_step();
  246. fprintf(stderr, "Error: The index of %s() is out of the bounds.\n", __FUNCTION__);
  247. return NULL;
  248. }
  249. BoneRequest *request = malloc(sizeof(BoneRequest));
  250. request->type = C_SKIN_GET_BONE_POSITION;
  251. request->bone_index = index;
  252. request->absolute = absolute;
  253. request->next = NULL;
  254. add_request(skin, request);
  255. wb_robot_flush_unlocked();
  256. robot_mutex_unlock_step();
  257. return skin->bone_position;
  258. }
  259. const double *wb_skin_get_bone_orientation(WbDeviceTag tag, int index, bool absolute) {
  260. Skin *skin = skin_get_struct(tag);
  261. if (!skin) {
  262. fprintf(stderr, "Error: %s(): invalid device tag.\n", __FUNCTION__);
  263. return NULL;
  264. }
  265. robot_mutex_lock_step();
  266. // Check if joint index is valid
  267. if (index < 0 || index >= skin->bone_count) {
  268. robot_mutex_unlock_step();
  269. fprintf(stderr, "Error: The index of %s() is out of the bounds.\n", __FUNCTION__);
  270. return NULL;
  271. }
  272. BoneRequest *request = malloc(sizeof(BoneRequest));
  273. request->type = C_SKIN_GET_BONE_ORIENTATION;
  274. request->bone_index = index;
  275. request->absolute = absolute;
  276. request->next = NULL;
  277. add_request(skin, request);
  278. wb_robot_flush_unlocked();
  279. robot_mutex_unlock_step();
  280. return skin->bone_orientation;
  281. }