U.B.O.R
The [U]seless [B]ox [O]rganizing [R]obot. A FreeRTOS study project written in C which implements a multitasked control unit for a belt conveyor system with robotic sorting arms.
arm.c
Go to the documentation of this file.
1 /*****************************************************************************
2  *
3  * This program is free software; you can redistribute it and/or
4  * modify it under the terms of the GNU General Public License
5  * as published by the Free Software Foundation; either version 2
6  * of the License, or (at your option) any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
16  * MA 02110-1301, USA.
17  *
18  *****************************************************************************/
19 
25 
26 //----- Header-Files -----------------------------------------------------------
27 #include <stdio.h>
28 
29 #include <FreeRTOS.h>
30 #include <task.h>
31 #include <queue.h>
32 #include <semphr.h>
33 #include <timers.h>
34 #include <memPoolService.h>
35 #include <stdbool.h>
36 
37 #include <carme_io1.h>
38 
39 #include "arm.h"
40 #include "ucan.h"
41 #include "bcs.h"
42 
43 //----- Macros -----------------------------------------------------------------
44 #define BUTTON_T0 0x01
45 #define BUTTON_T1 0x02
46 #define BUTTON_T2 0x04
47 #define BUTTON_T3 0x08
48 
49 // Left
50 #define ROBOT_L_STATUS_REQUEST_ID 0x150
51 #define ROBOT_L_STATUS_RETURN_ID 0x151
52 #define ROBOT_L_COMAND_REQUEST_ID 0x152
53 #define ROBOT_L_COMAND_RETURN_ID 0x153
54 #define ROBOT_L_RESET_ID 0x15F
55 #define COMAND_DLC 0x006
56 #define STATUS_REQEST_DLC 0x002
57 
58 
59 // Right
60 #define ROBOT_R_STATUS_REQUEST_ID 0x160
61 #define ROBOT_R_STATUS_RETURN_ID 0x161
62 #define ROBOT_R_COMAND_REQUEST_ID 0x162
63 #define ROBOT_R_COMAND_RETURN_ID 0x163
64 #define ROBOT_R_RESET_ID 0x16F
65 
66 #define MASK_SWITCH_0 0x01
67 #define MASK_SWITCH_1 0x02
68 #define MASK_SWITCH_2 0x04
69 #define MASK_SWITCH_3 0x08
70 #define MASK_SWITCH_4 0x10
71 
72 
73 #define BLOCK_TIME_MIDDLE_POS 200000 // block time for mutex midle position
74 #define MSG_QUEUE_SIZE 1
75 #define ARM_TASK_PRIORITY 2
76 #define ARM_TASK_STACKSIZE 256
77 #define TASK_DELAY 100
78 #define GRIPPER_MAX 1
79 #define GRIPPER_MIN 0
80 
86  };
87 
88 //----- Data types -------------------------------------------------------------
89 
90 //----- Function prototypes ----------------------------------------------------
91 static void wait_until_pos(uint8_t *pos, enum arm_select side);
92 
93 //----- Data -------------------------------------------------------------------
94 static QueueHandle_t robot_left_queue;
95 static QueueHandle_t robot_right_queue;
96 static QueueHandle_t robot_manual_queue;
97 
98 static SemaphoreHandle_t arm_mid_air_mutex;
99 
100 CARME_CAN_MESSAGE robot_msg_buffer_right;
101 CARME_CAN_MESSAGE robot_msg_buffer_left;
102 
103 uint8_t status_request[2] = {0x02,0x00};
104 
105 //----- Implementation ---------------------------------------------------------
106 
118 static void arm_enter_critical_air_space()
119 {
120  display_log(DISPLAY_NEWLINE, "take semaphore mid");
121  xSemaphoreTake(arm_mid_air_mutex, portMAX_DELAY); //to protect the airspace around mid
122 }
123 
135 static void arm_leave_critical_air_space()
136 {
137  display_log(DISPLAY_NEWLINE, "give semaphore mid");
138  xSemaphoreGive(arm_mid_air_mutex);
139 }
140 
141 
151 void move_roboter(void *pv_data)
152 {
153 
154  enum arm_select left_right_sel = (enum arm_select)pv_data;
155  uint8_t *pos_arm;
156  int id_arm_comand_request;
157 
158  /* Init */
159  if(left_right_sel == arm_right) {
160  static uint8_t pos_arm_right[11][6] = {
161  /* Arm B S E H G */
162  /*0 Nullposition */ {0x02, 0x00, 0x19, 0x1A, 0x21, 0x01},
163  /*1 StartPosition */ {0x02, 0x00, 0x1F, 0x1A, 0x21, 0x01},
164  /*2 Zp1 FB Links */ {0x02, 0x00, 0x1F, 0x1A, 0x21, 0x00},
165  /*3 Zp2 FB Links */ {0x02, 0x00, 0x19, 0x1A, 0x21, 0x00},
166  /*4 G offen FB Links */ {0x02, 0xee, 0x00, 0x40, 0x21, 0x00},
167  /*5 G zu FB Links */ {0x02, 0xD2, 0x00, 0x2b, 0x21, 0x00},
168  /*6 Zp1 FB Mitte */ {0x02, 0xD2, 0x1c, 0x1d, 0x21, 0x00},
169  /*7 Zp2 FB Mitte */ {0x02, 0xD2, 0x1c, 0x1d, 0x21, 0x01},
170  /*8 G zu FB Mitte */ {0x02, 0xD2, 0x13, 0x1d, 0x21, 0x01},
171  /*9 G offen FB Mitte */ {0x02, 0xD2, 0x00, 0x36, 0x21, 0x01},
172  {0x02, 0xEE, 0x00, 0x36, 0x21, 0x01},
173  };
174 
175  arm_mid_air_mutex = xSemaphoreCreateBinary();
176  xSemaphoreGive(arm_mid_air_mutex);
177 
178  robot_right_queue = xQueueCreate(MSG_QUEUE_SIZE, sizeof(CARME_CAN_MESSAGE));
180 
181  pos_arm = (uint8_t *)pos_arm_right;
182  id_arm_comand_request = ROBOT_R_COMAND_REQUEST_ID;
183 
185  }
186 
187  if(left_right_sel == arm_left) {
188  static uint8_t pos_arm_left[11][6] = {
189  /* Arm B S E H G x x */
190  {0x02, 0x00, 0x19, 0x1A, 0x21, 0x01}, //Warte Position ECTS Abholen
191  {0x02, 0x00, 0x1F, 0x1A, 0x21, 0x01}, //ECTS Holen Mitte
192  {0x02, 0x00, 0x1F, 0x1A, 0x21, 0x00}, //ECTS Greifen
193  {0x02, 0x00, 0x19, 0x1A, 0x21, 0x00}, //ECTS Anheben
194  {0x02, 0x12, 0x00, 0x40, 0x21, 0x00}, //Drehen bis pos 1
195  {0x02, 0x2D, 0x00, 0x2b, 0x21, 0x00}, //Drehen bis pos 2 bereit zum ablegen
196  {0x02, 0x2D, 0x1c, 0x1d, 0x21, 0x00}, //ECTS Ablegen
197  {0x02, 0x2D, 0x1c, 0x1d, 0x21, 0x01}, //ECTS Ablegen
198  {0x02, 0x2D, 0x13, 0x1d, 0x21, 0x01}, //Arm auserhalb ects
199  {0x02, 0x2D, 0x00, 0x36, 0x21, 0x01}, //Arm ausserhalb mitte
200  {0x02, 0x12, 0x00, 0x36, 0x21, 0x01}, //Arm ausserhalb mitte
201  };
202 
203  pos_arm = (uint8_t *)pos_arm_left;
204  id_arm_comand_request = ROBOT_L_COMAND_REQUEST_ID;
205 
206  robot_left_queue = xQueueCreate(MSG_QUEUE_SIZE, sizeof(CARME_CAN_MESSAGE));
208 
210  }
211 
212  vTaskDelay(500); //needed for reset to be applied
213 
214  while(1) {
215 
216  for(int n = 0; n < 11; n++) {
217  display_log(DISPLAY_NEWLINE, "Going to position %u",n);
218 
219  //before we want to grab the block
220  if(n==1) {
221  int8_t pos;
222  pos = bcs_grab(left_right_sel);
223  display_log(DISPLAY_NEWLINE,"block is at pos %d",pos);
224  }
225 
226  if(n == 6) { //before we want to access the mid position
227  arm_enter_critical_air_space();
228  }
229 
230  if(n==7) { //before we open the grip (to drop the block)
232  }
233 
234 
235 
236  ucan_send_data(COMAND_DLC, id_arm_comand_request, &pos_arm[n*6] );
237  wait_until_pos(&pos_arm[n*6], left_right_sel);
238 
239  if(n==3) { //after we picked up a block
240  bcs_signal_band_free(left_right_sel);
241  }
242 
243  if(n== 8) { //after we dropped a block
245  }
246 
247  if(n == 9) { //after we moved out of the mid position
248  arm_leave_critical_air_space();
249  }
250 
251 
252  vTaskDelay(TASK_DELAY);
253  }
254  }
255 }
256 
267 static void wait_until_pos(uint8_t *pos, enum arm_select side)
268 {
269  uint8_t *temp = (uint8_t *)pos;
270  bool close_enough = false;
271 
272  if(side == arm_right) {
273  //display_log(DISPLAY_NEWLINE, "Right arm wait until position reached");
274 
275  while(close_enough != true) {
276  vTaskDelay(200);
278 
279 
280  xQueueReceive(robot_right_queue, (void *)&robot_msg_buffer_right, portMAX_DELAY);
281  close_enough = true;
282  for(int i=1; i<6; i++) {
283  if(abs(temp[i]-robot_msg_buffer_right.data[i])>0x01) {
284  close_enough = false;
285  break;
286  }
287  }
288 
289  }
290  //display_log(DISPLAY_NEWLINE, "Right arm reached position");
291  } else {
292  //display_log(DISPLAY_NEWLINE, "Left arm wait until position reached");
293  while(close_enough != true) {
294 
295  vTaskDelay(200);
296 
298 
299  xQueueReceive(robot_left_queue, (void *)&robot_msg_buffer_left, portMAX_DELAY);
300  close_enough = true;
301  for(int i=1; i<6; i++) {
302  if(abs(temp[i]-robot_msg_buffer_left.data[i])>0x01) {
303  close_enough = false;
304  break;
305  }
306  }
307  }
308 
309  //display_log(DISPLAY_NEWLINE, "Left arm reached position");
310  }
311  vTaskDelay(1000);
312 }
313 
323 void init_arm()
324 {
325 
326  xTaskCreate(move_roboter,
327  "Arm Left",
329  (void*)arm_left,
331  NULL);
332 
333  xTaskCreate(move_roboter,
334  "Arm Right",
336  (void*)arm_right,
338  NULL);
339  /*
340  xTaskCreate(manual_arm_movement,
341  "Manual Arm Movement",
342  ARM_TASK_STACKSIZE,
343  NULL,
344  ARM_TASK_PRIORITY,
345  NULL);*/
346 }
347 
358 void manual_arm_movement(void *pvData)
359 {
360  /*
361  * Switch 0: select left or right arm
362  * Switch 1: increment or decrement position value
363  * Switch 2: gripper open or close
364  *
365  * Button 0: change value of basis
366  * Button 1: change value of shoulder
367  * Button 2: change value of elbow
368  * Button 3: change value of hand
369  */
370 
371  uint8_t button_data;
372  uint8_t switch_data;
373 
374  uint8_t pos_manuel[6] = {0x02, 0x00, 0x00, 0x00, 0x00, 0x00};
375  bool increment = false;
376  bool left_select = false;
377 
378  CARME_CAN_MESSAGE robot_msg_buffer_manual;
379  robot_manual_queue = xQueueCreate(MSG_QUEUE_SIZE, sizeof(CARME_CAN_MESSAGE));
382 
383  while(1) {
384  CARME_IO1_BUTTON_Get(&button_data);
385  CARME_IO1_SWITCH_Get(&switch_data);
386 
387  if( (switch_data & MASK_SWITCH_0) != 0) {
388  left_select = true;
389  } else {
390  left_select = false;
391  }
392 
393  if( (switch_data & MASK_SWITCH_1 ) != 0) {
394  increment = true;
395  } else {
396  increment = false;
397  }
398 
399  if( (switch_data & MASK_SWITCH_2) != 0) {
400  pos_manuel[5] = GRIPPER_MAX;
401  } else {
402  pos_manuel[5] = GRIPPER_MIN;
403  }
404 
405  switch(button_data) {
406 
407  case BUTTON_T0:
408  if(increment == true) {
409  pos_manuel[1]++;
410  } else {
411  pos_manuel[1]--;
412  }
413  break;
414 
415  case BUTTON_T1:
416  if(increment == true) {
417  pos_manuel[2]++;;
418  } else {
419  pos_manuel[2]--;
420  }
421  break;
422 
423  case BUTTON_T2:
424  if(increment == true) {
425  pos_manuel[3]++;
426  } else {
427  pos_manuel[3]--;
428  }
429  break;
430 
431  case BUTTON_T3:
432  if(increment == true) {
433  pos_manuel[4]++;
434  } else {
435  pos_manuel[4]--;
436  }
437  break;
438  default:
439  break;
440  }
441 
442  if(left_select == true) {
444  vTaskDelay(20);
446  vTaskDelay(20);
447  xQueueReceive(robot_manual_queue, (void *)&robot_msg_buffer_manual, portMAX_DELAY);
448  vTaskDelay(20);
449  } else {
451  vTaskDelay(20);
453  xQueueReceive(robot_manual_queue, (void *)&robot_msg_buffer_manual, portMAX_DELAY);
454  vTaskDelay(20);
455  }
456 
457  display_log(DISPLAY_NEWLINE,"Position: %x %x %x %x %x %x",robot_msg_buffer_right.data[0],
458  robot_msg_buffer_manual.data[1],
459  robot_msg_buffer_manual.data[2],
460  robot_msg_buffer_manual.data[3],
461  robot_msg_buffer_manual.data[4],
462  robot_msg_buffer_manual.data[5]);
463  }
464 }
465 
#define DISPLAY_NEWLINE
Definition: display.h:10
void bcs_signal_band_free(enum belt_select belt)
Signal that a block has been removed from a belt and the belt is free again global.
Definition: bcs.c:223
void manual_arm_movement(void *pvData)
Task to move the roboter with the Buttons. To create this task unkomment it in the function init_arm(...
Definition: arm.c:358
#define ROBOT_R_STATUS_RETURN_ID
Definition: arm.c:61
#define BUTTON_T2
Definition: arm.c:46
#define GRIPPER_MAX
Definition: arm.c:78
the left arm
Definition: arm.c:84
the right belt
Definition: bcs.h:10
#define ROBOT_R_RESET_ID
Definition: arm.c:64
uint8_t status_request[2]
Definition: arm.c:103
#define MASK_SWITCH_2
Definition: arm.c:68
#define MASK_SWITCH_0
Definition: arm.c:66
#define MASK_SWITCH_1
Definition: arm.c:67
void move_roboter(void *pv_data)
Task for left and right arm.
Definition: arm.c:151
#define BUTTON_T1
Definition: arm.c:45
bool ucan_link_message_to_queue(uint16_t message_id, QueueHandle_t queue)
Link a single message type to a queue global.
Definition: ucan.c:202
#define MSG_QUEUE_SIZE
Definition: arm.c:74
void bcs_signal_dropped(enum belt_select belt)
Signal that a block has been dropped on a belt global.
Definition: bcs.c:201
#define BUTTON_T0
Definition: arm.c:44
the right arm
Definition: arm.c:85
bool ucan_send_data(uint8_t n_data_bytes, uint16_t msg_id, const uint8_t *data)
Send data to the can output message queue global.
Definition: ucan.c:264
the left belt
Definition: bcs.h:8
#define STATUS_REQEST_DLC
Definition: arm.c:56
#define TASK_DELAY
Definition: arm.c:77
void bcs_prepare_drop(enum belt_select belt)
Prepares a block drop operation to a specific belt global.
Definition: bcs.c:178
#define ROBOT_L_STATUS_REQUEST_ID
Definition: arm.c:50
uint8_t display_log(uint8_t id, const char *fmtstr,...)
Logs a message to the display global.
Definition: display.c:70
#define ROBOT_R_STATUS_REQUEST_ID
Definition: arm.c:60
the middle belt
Definition: bcs.h:9
#define ROBOT_L_RESET_ID
Definition: arm.c:54
#define ROBOT_R_COMAND_REQUEST_ID
Definition: arm.c:62
int8_t bcs_grab(enum belt_select belt)
Instructs the system that we want to grab a block from the bcs global.
Definition: bcs.c:276
#define ROBOT_L_COMAND_REQUEST_ID
Definition: arm.c:52
#define ARM_TASK_PRIORITY
Definition: arm.c:75
CARME_CAN_MESSAGE robot_msg_buffer_left
Definition: arm.c:101
arm_select
The arm_select enum differenciates between the different arms (left/right)
Definition: arm.c:84
#define ROBOT_L_STATUS_RETURN_ID
Definition: arm.c:51
#define BUTTON_T3
Definition: arm.c:47
#define GRIPPER_MIN
Definition: arm.c:79
void init_arm()
Creates the arm tasks.
Definition: arm.c:323
#define COMAND_DLC
Definition: arm.c:55
#define ARM_TASK_STACKSIZE
Definition: arm.c:76
CARME_CAN_MESSAGE robot_msg_buffer_right
Definition: arm.c:100