MercurySDK
Software development kit for Mercury digital servos
clear_multi_turn.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2 * Copyright (C) 2021 <Robot Articulation/code@robotarticulation.com>
3 *
4 * Source files modified to support the Mercury range of digital servo motors from Robot Articulation
5 *******************************************************************************/
6 
7 /*******************************************************************************
8 * Copyright 2017 ROBOTIS CO., LTD.
9 *
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
13 *
14 * http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
21 *******************************************************************************/
22 
23 //
24 // ********* Clear Multiturn Example *********
25 //
26 // This example is tested with a Mercury M1, and a USB2Mercury
27 //
28 
29 #if defined(__linux__) || defined(__APPLE__)
30 #include <fcntl.h>
31 #include <termios.h>
32 #include <unistd.h>
33 #define STDIN_FILENO 0
34 #elif defined(_WIN32) || defined(_WIN64)
35 #include <conio.h>
36 #endif
37 
38 #include <stdlib.h>
39 #include <stdio.h>
40 
41 #include "mercury_sdk.h" // Uses Mercury SDK library
42 
43 // Control table address
44 #define ADDR_OPERATING_MODE 0x06 // Control table address is different in Mercury model
45 #define ADDR_TORQUE_ENABLE 0x30
46 #define ADDR_GOAL_POSITION 0x4e
47 #define ADDR_PRESENT_POSITION 0x5a
48 
49 // Protocol version
50 #define PROTOCOL_VERSION 2.0 // See which protocol version is used in the Mercury
51 
52 // Default setting
53 #define MCY_ID 1 // Mercury ID: 1
54 #define BAUDRATE 1000000
55 #define DEVICENAME "/dev/ttyACM1" // Check which port is being used on your controller
56  // eg: Windows: "COM1" Linux: "/dev/ttyACM0"
57 
58 #define TORQUE_ENABLE 1 // Value for enabling the torque
59 #define TORQUE_DISABLE 0 // Value for disabling the torque
60 #define MAX_POSITION_VALUE -1
61 #define DXL_MOVING_STATUS_THRESHOLD 20 // Mercury moving status threshold
62 #define EXT_POSITION_CONTROL_MODE 3 // Value for extended position control mode (operating mode)
63 
64 #define ESC_ASCII_VALUE 0x1b
65 #define SPACE_ASCII_VALUE 0x20
66 
67 int getch()
68 {
69 #if defined(__linux__) || defined(__APPLE__)
70  struct termios oldt, newt;
71  int ch;
72  tcgetattr(STDIN_FILENO, &oldt);
73  newt = oldt;
74  newt.c_lflag &= ~(ICANON | ECHO);
75  tcsetattr(STDIN_FILENO, TCSANOW, &newt);
76  ch = getchar();
77  tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
78  return ch;
79 #elif defined(_WIN32) || defined(_WIN64)
80  return _getch();
81 #endif
82 }
83 
84 int kbhit(void)
85 {
86 #if defined(__linux__) || defined(__APPLE__)
87  struct termios oldt, newt;
88  int ch;
89  int oldf;
90 
91  tcgetattr(STDIN_FILENO, &oldt);
92  newt = oldt;
93  newt.c_lflag &= ~(ICANON | ECHO);
94  tcsetattr(STDIN_FILENO, TCSANOW, &newt);
95  oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
96  fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);
97 
98  ch = getchar();
99 
100  tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
101  fcntl(STDIN_FILENO, F_SETFL, oldf);
102 
103  if (ch != EOF)
104  {
105  ungetc(ch, stdin);
106  return 1;
107  }
108 
109  return 0;
110 #elif defined(_WIN32) || defined(_WIN64)
111  return _kbhit();
112 #endif
113 }
114 
115 void msecSleep(int waitTime)
116 {
117 #if defined(__linux__) || defined(__APPLE__)
118  usleep(waitTime * 1000);
119 #elif defined(_WIN32) || defined(_WIN64)
120  _sleep(waitTime);
121 #endif
122 }
123 
124 int main()
125 {
126  // Initialize PortHandler instance
127  // Set the port path
128  // Get methods and members of PortHandlerLinux or PortHandlerWindows
130 
131  // Initialize PacketHandler instance
132  // Set the protocol version
133  // Get methods and members of Protocol1PacketHandler or Protocol2PacketHandler
135 
136  int mcy_comm_result = COMM_TX_FAIL; // Communication result
137 
138  uint8_t mcy_error = 0; // Mercury error
139  int32_t mcy_present_position = 0; // Present position
140 
141  // Open port
142  if (portHandler->openPort())
143  {
144  printf("Succeeded to open the port!\n");
145  }
146  else
147  {
148  printf("Failed to open the port!\n");
149  printf("Press any key to terminate...\n");
150  getch();
151  return 0;
152  }
153 
154  // Set port baudrate
155  if (portHandler->setBaudRate(BAUDRATE))
156  {
157  printf("Succeeded to change the baudrate!\n");
158  }
159  else
160  {
161  printf("Failed to change the baudrate!\n");
162  printf("Press any key to terminate...\n");
163  getch();
164  return 0;
165  }
166 
167  uint8_t operating_mode = 0;
168  mcy_comm_result = packetHandler->readTxRx(portHandler, MCY_ID, ADDR_OPERATING_MODE, 0x01, &operating_mode, &mcy_error);
169  if (mcy_comm_result != COMM_SUCCESS)
170  {
171  printf("%s\n", packetHandler->getTxRxResult(mcy_comm_result));
172  }
173  else if (mcy_error != 0)
174  {
175  printf("%s\n", packetHandler->getRxPacketError(mcy_error));
176  }
177  else
178  {
179  if (operating_mode != EXT_POSITION_CONTROL_MODE)
180  {
181  mcy_comm_result = packetHandler->write1ByteTxRx(portHandler, MCY_ID, ADDR_TORQUE_ENABLE, 0, &mcy_error);
182  if (mcy_comm_result != COMM_SUCCESS)
183  {
184  printf("%s\n", packetHandler->getTxRxResult(mcy_comm_result));
185  }
186  else if (mcy_error != 0)
187  {
188  printf("%s\n", packetHandler->getRxPacketError(mcy_error));
189  }
190  else
191  {
192  printf("Control_enable has been disabled \n");
193  }
194 
195 
196  // Set operating mode to extended position control mode
197  mcy_comm_result = packetHandler->write1ByteTxRx(portHandler, MCY_ID, ADDR_OPERATING_MODE, EXT_POSITION_CONTROL_MODE, &mcy_error);
198  if (mcy_comm_result != COMM_SUCCESS)
199  {
200  printf("%s\n", packetHandler->getTxRxResult(mcy_comm_result));
201  }
202  else if (mcy_error != 0)
203  {
204  printf("%s\n", packetHandler->getRxPacketError(mcy_error));
205  }
206  else
207  {
208  // This is a rom write, so add a delay of 1s
209  usleep(1e06);
210  printf("Operating mode changed to extended position control mode. \n");
211  }
212  }
213  }
214 
215  // Enable Mercury Torque
216  mcy_comm_result = packetHandler->write1ByteTxRx(portHandler, MCY_ID, ADDR_TORQUE_ENABLE, TORQUE_ENABLE, &mcy_error);
217  if (mcy_comm_result != COMM_SUCCESS)
218  {
219  printf("%s\n", packetHandler->getTxRxResult(mcy_comm_result));
220  }
221  else if (mcy_error != 0)
222  {
223  printf("%s\n", packetHandler->getRxPacketError(mcy_error));
224  }
225  else
226  {
227  printf("Mercury has been successfully connected \n");
228  }
229 
230  while(1)
231  {
232  printf(" Press SPACE key to clear multi-turn information! (or press ESC to quit!)\n");
233 
234  // Write goal position
235  mcy_comm_result = packetHandler->write4ByteTxRx(portHandler, MCY_ID, ADDR_GOAL_POSITION, MAX_POSITION_VALUE, &mcy_error);
236  if (mcy_comm_result != COMM_SUCCESS)
237  {
238  printf("%s\n", packetHandler->getTxRxResult(mcy_comm_result));
239  }
240  else if (mcy_error != 0)
241  {
242  printf("%s\n", packetHandler->getRxPacketError(mcy_error));
243  }
244 
245  do
246  {
247  // Read present position
248  mcy_comm_result = packetHandler->read4ByteTxRx(portHandler, MCY_ID, ADDR_PRESENT_POSITION, (uint32_t*)&mcy_present_position, &mcy_error);
249  if (mcy_comm_result != COMM_SUCCESS)
250  {
251  printf("%s\n", packetHandler->getTxRxResult(mcy_comm_result));
252  }
253  else if (mcy_error != 0)
254  {
255  printf("%s\n", packetHandler->getRxPacketError(mcy_error));
256  }
257 
258  printf("[ID:%03d] GoalPos:%03d PresPos:%03d \n", MCY_ID, MAX_POSITION_VALUE, mcy_present_position);
259 
260  usleep(10000);
261 
262  }while((abs(MAX_POSITION_VALUE - mcy_present_position) > DXL_MOVING_STATUS_THRESHOLD));
263 
264  // we've reached the goal position
265 
266  char c = getch();
267  if (c == SPACE_ASCII_VALUE)
268  {
269  printf("\n Clearing Multi-Turn Information... \n");
270 
271  //printf("[ID:%03d] GoalPos:%03d New PresPos:%03d \n", MCY_ID, MAX_POSITION_VALUE, (mcy_present_position - 8192) % 16384);
272 
273  // Clear Multi-Turn Information
274  mcy_comm_result = packetHandler->clearMultiTurn(portHandler, MCY_ID, &mcy_error);
275  if (mcy_comm_result != COMM_SUCCESS)
276  {
277  printf("%s\n", packetHandler->getTxRxResult(mcy_comm_result));
278  }
279  else if (mcy_error != 0)
280  {
281  printf("%s\n", packetHandler->getRxPacketError(mcy_error));
282  }
283 
284  printf("[ID:%03d] GoalPos:%03d New PresPos:%03d \n", MCY_ID, MAX_POSITION_VALUE, (mcy_present_position - 8192) % 16384);
285 
286  // Write the present position to the goal position. This will move servo to same position after x number of revolutions
287  mcy_comm_result = packetHandler->write4ByteTxRx(portHandler, MCY_ID, ADDR_GOAL_POSITION, mcy_present_position, &mcy_error);
288  if (mcy_comm_result != COMM_SUCCESS)
289  {
290  printf("%s\n", packetHandler->getTxRxResult(mcy_comm_result));
291  }
292  else if (mcy_error != 0)
293  {
294  printf("%s\n", packetHandler->getRxPacketError(mcy_error));
295  }
296 
297  msecSleep(300);
298  }
299  else if (c == ESC_ASCII_VALUE)
300  break;
301 
302  do
303  {
304  // Read present position
305  mcy_comm_result = packetHandler->read4ByteTxRx(portHandler, MCY_ID, ADDR_PRESENT_POSITION, (uint32_t*)&mcy_present_position, &mcy_error);
306  if (mcy_comm_result != COMM_SUCCESS)
307  {
308  printf("%s\n", packetHandler->getTxRxResult(mcy_comm_result));
309  }
310  else if (mcy_error != 0)
311  {
312  printf("%s\n", packetHandler->getRxPacketError(mcy_error));
313  }
314  usleep(1000);
315 
316  }while((abs(MAX_POSITION_VALUE - mcy_present_position) > DXL_MOVING_STATUS_THRESHOLD));
317  }
318 
319  // Disable Mercury Torque
320  mcy_comm_result = packetHandler->write1ByteTxRx(portHandler, MCY_ID, ADDR_TORQUE_ENABLE, TORQUE_DISABLE, &mcy_error);
321  if (mcy_comm_result != COMM_SUCCESS)
322  {
323  printf("%s\n", packetHandler->getTxRxResult(mcy_comm_result));
324  }
325  else if (mcy_error != 0)
326  {
327  printf("%s\n", packetHandler->getRxPacketError(mcy_error));
328  }
329 
330  // Close port
331  portHandler->closePort();
332 
333  return 0;
334 }
The class that inherits Protocol1PacketHandler class or Protocol2PacketHandler class.
virtual const char * getTxRxResult(int result)=0
The function that gets description of communication result.
virtual int write1ByteTxRx(PortHandler *port, uint8_t id, uint16_t address, uint8_t data, uint8_t *error=0)=0
The function that calls PacketHandler::writeTxRx() for writing 1 byte data and receives the packet @d...
virtual const char * getRxPacketError(uint8_t error)=0
The function that gets description of hardware error.
virtual int read4ByteTxRx(PortHandler *port, uint8_t id, uint16_t address, uint32_t *data, uint8_t *error=0)=0
The function that calls PacketHandler::readTxRx() function for reading 4 byte data @description The f...
virtual int clearMultiTurn(PortHandler *port, uint8_t id, uint8_t *error=0)=0
The function that resets the multi-turn revolution count @description The function makes an instructi...
virtual int readTxRx(PortHandler *port, uint8_t id, uint16_t address, uint16_t length, uint8_t *data, uint8_t *error=0)=0
The function that transmits INST_READ instruction packet, and read data from received packet @descrip...
virtual int write4ByteTxRx(PortHandler *port, uint8_t id, uint16_t address, uint32_t data, uint8_t *error=0)=0
The function that calls PacketHandler::writeTxRx() for writing 4 byte data and receives the packet @d...
static PacketHandler * getPacketHandler()
The function that returns PacketHandler instance.
The class for port control that inherits PortHandlerLinux, PortHandlerWindows, PortHandlerMac,...
Definition: port_handler.h:56
static PortHandler * getPortHandler(const char *port_name)
The function that gets PortHandler class inheritance @description The function gets class inheritance...
virtual bool openPort()=0
The function that opens the port @description The function calls PortHandlerLinux::setBaudRate() to o...
virtual bool setBaudRate(const int baudrate)=0
The function that sets baudrate into the port handler @description The function sets baudrate into th...
virtual void closePort()=0
The function that closes the port @description The function closes the port.
int getch()
#define EXT_POSITION_CONTROL_MODE
#define ADDR_PRESENT_POSITION
void msecSleep(int waitTime)
#define ADDR_OPERATING_MODE
#define ESC_ASCII_VALUE
#define BAUDRATE
#define DXL_MOVING_STATUS_THRESHOLD
#define ADDR_GOAL_POSITION
#define SPACE_ASCII_VALUE
#define TORQUE_ENABLE
int kbhit(void)
#define MCY_ID
#define DEVICENAME
int main()
#define ADDR_TORQUE_ENABLE
#define MAX_POSITION_VALUE
#define TORQUE_DISABLE
#define COMM_SUCCESS
#define COMM_TX_FAIL