====== How to Program Wii Remote to Control DARwIn-OP ====== **Author:** Fausto Vega **Email:** \\ **Author:** Yu Hang He ** Email: ** \\ **Reviewed by:** Jean Vaz ** Email: ** **Date:** Last modified on <04/20/19> \\ **Keywords:** Dynamixels , C/Cpp Programming, Wii Remote, Humanoid robot, DARwIn-OP The objective of the tutorial is to control DARwIn-OP with a Wii controller. Solving this partially or completely is important because it allows one to access data from the internal sensors in the Wii remote and use the inputs on the Wii remote to control DARwIn-OP. This tutorial shows you the procedure and the program to access the data from the Wii remote, use inputs from Wii remote to control DARwIn-OP, and provides a demonstration of the final result. \\ ===== Motivation and Audience ===== This tutorial's motivation is to teach the audience how to detect inputs on the Wii remote and use those inputs to control DARwIn-OP. The Wii remote is connected to a laptop using Bluetooth. A client program on the laptop will receive inputs from the Wii remote, then send the signals via a TCP network model to a server program on DARwIn-OP to control its action. Readers of this tutorial assumes the reader has the following background and interests: * Know how to program using Cpp language \\ * Familiar with Linux terminal \\ * Familiar with programming structure of DARwIn-OP \\ * This tutorial may also attract readers who are interested in using Wii remote as a controller for any program \\ \\ The rest of this tutorial is presented as follows: * [[wiimote_button_action#Other_Tutorials_and_References | Other Tutorials and References]] * [[wiimote_button_action#Programming| Programming]] * [[wiimote_button_action#Instructions | Instructions]] * [[wiimote_button_action#Demonstration | Demonstration]] * [[wiimote_button_action#Final_Words | Final Words]] ===== Other Tutorials and References===== For a more in depth explanation of network programming (TCP client server program) refer to the following tutorial: *[[tcp_udp|TCP & UDP Communications]] For a quick guide to using network programming on DARwIn-OP refer to the following tutorial *[[vega_darwin|Darwin OP Master Slave]] For a guide to accessing acceleration data on Wii remote and use it to control Dynamixel motor refer to the following tutorial: *[[vega_wii|Controlling Dynamixel's with a Wii Remote]] The procedures for downloading the Wii remote driver, connecting Wii remote to a computer through Bluetooth, and source code for accessing Wii remote data and use it to control Dynamixels are presented in the last tutorial. **It is highly recommended that the reader read and complete the last tutorial before proceeding** since the information will not be repeated in this tutorial. ===== Programming ===== This section will highlight some important part of the code in the programs. The full programs are available in the Source Code section. //Line 82 static void wii_event(const struct xwii_event *event, int sockfd) { int n, reply[1]; //array that stores the states of key and acceleration data int arg[8] = {0}; //in event struct, v is an union that stores data payload //key struct continas the enumerated key number and key state //store key number in code and state as a bool pressed (0 false, 1 true) unsigned int code = event->v.key.code; bool pressed = event->v.key.state; //Use switch case to cycle through wiimote events switch(event->type) { case XWII_EVENT_KEY: //if the respective key are pressed, the state is set to 1, otherwise 0 if(pressed) { if (code == XWII_KEY_LEFT) arg[2] = 1; else arg[2] = 0; if (code == XWII_KEY_RIGHT) arg[3] = 1; else arg[3] = 0; if (code == XWII_KEY_UP) arg[4] = 1; else arg[4] = 0; if (code == XWII_KEY_DOWN) arg[5] = 1; else arg[5] = 0; } else { for(int i = 2; i < 6; i++) arg[i] = 0; } //key A and B act as switches for performing actions, the sleep() was used to pause the program while action is performed if (code == XWII_KEY_A) if(pressed) { arg[6] = -arg[6]; sleep(1); } if (code == XWII_KEY_B) if(pressed) { arg[7] = -arg[7]; sleep(1); } break; case XWII_EVENT_ACCEL: //abs struct contains absolute motion event payload, x stores roll, while y stores pitch if(arg[7] == 1) { arg[0] = event->v.abs[0].x*val2deg; arg[1] = event->v.abs[0].y*val2deg; } else { arg[0] = 0; arg[1] = 0; } break; } //send motion data to server using socket n = write(sockfd, arg, sizeof(arg)); if (n < 0) error("ERROR writing to socket"); bzero(reply,sizeof(reply)); n = read(sockfd,reply,sizeof(reply)); if (n < 0) error("ERROR reading from socket"); } //Line 135 //store the initial position of dynamixel cm730.ReadWord(JointData::ID_L_SHOULDER_PITCH, MX28::P_PRESENT_POSITION_L, &pitchpos, 0); cm730.ReadWord(JointData::ID_L_SHOULDER_ROLL, MX28::P_PRESENT_POSITION_L, &rollpos, 0); while (1) { //read TCP data from client and store it in disp[] array n = read(newsockfd,disp,sizeof(disp)); if (n < 0) error("ERROR reading from socket"); //new position for shoulder roll and pitch dynamixel is the sum of initial position and angle inputs from Wii remote r_pos = rollpos+11.378*disp[0]; p_pos = pitchpos+11.378*disp[1]; if (disp[7] ==1) { Action::GetInstance()->m_Joint.SetEnableBody(false, false); MotionManager::GetInstance()->SetEnable(false); //dynamixel limits if (rollpos>=2460 || rollpos<=1200) printf("Limit has been reached"); else cm730.WriteWord(JointData::ID_L_SHOULDER_ROLL, MX28::P_GOAL_POSITION_L, r_pos, 0); //move shoulder roll //dynamixel limits if (pitchpos<0 || pitchpos>3038) printf("Limit has been reached"); else cm730.WriteWord(JointData::ID_L_SHOULDER_PITCH, MX28::P_GOAL_POSITION_L, p_pos, 0); //move shoulder pitch } //disp[6] stores states of button A on Wii remote //integer stand and sit stores the state of DARwIn-OP if (disp[6] == 1) { if(stand == 0) { if(Action::GetInstance()->IsRunning() == 0) { Action::GetInstance()->m_Joint.SetEnableBody(true, true); MotionManager::GetInstance()->SetEnable(true); Action::GetInstance()->Start(9); stand = 1; sit = 0; } } } else if (disp[6] == -1) { if (sit == 0) { if(Action::GetInstance()->IsRunning() == 0) { Action::GetInstance()->m_Joint.SetEnableBody(true, true); MotionManager::GetInstance()->SetEnable(true); Action::GetInstance()->Start(15); sit = 1; stand = 0; } } } n = write(newsockfd,"0",1); if (n < 0) error("ERROR writing to socket"); } ===== Source Code ===== Below is the source code for the client and server used in the program. Download the xwiiacc.zip folder on a laptop and the darwin_wii_action.zip folder on the DARwIn-OP. The Wii remote will be used as input device to control DARwIn-OP *{{:yuhang:exo:xwiiacc.zip|}} *{{:yuhang:darwin_wii_action.zip|}} ===== Compiling the Client ===== If the xwiimote driver is successfully installed on the linux system, the library file libxwiimote.so should be installed in /usr/local/lib The program can be compiled direclty, however, the library file and header will need to be manually included in C compiler. Using terminal, navigate to the xwiiacc folder. While inside xwiiacc, execute the following command to compile the program: gcc main.cpp -o xwiiacc -L/~/usr/local/lib/ -lxwiimote The output program file is called xwiiacc. ===== Instructions ===== This section gives step-by-step instructions on how to run the program. Step 1: Run sudo su on Darwin OP (password is 111111) and navigate to the code folder with the following command; cd Desktop/darwin_wii_action/Linux/project/network_programming/ Then make the code : make Step 2 Once the program is built, make sure that both the client (laptop) and the server (Darwin OP) are connected to the same network. In this case it is “DASLWarehouse 2” Step 3 Run the server program by accessing the command prompt, navigating to the network programming folder (Step 1) and running the following command. ./server 5000 In this command, 5000 is the port number used for communication between the server and client. Step 4 Before running the client program, make sure the wii remote is laying still on a flat surface with the controls facing up. To run the client program on the laptop, access the command prompt and navigate to the folder where the xwiiacc program was compiled in the previous section. Enter the following commands to establish connection with the server: sudo ./xwiiacc 192.168.50.75 5000 1 Enter the password for ubuntu system to execute the program. Step 5 Once both server and client program is running, Press the B button on Wii remote to control the Dynamixel motor on DARwIn-OP. The Left shoulder pitch motor is controlled with the pitch motion of wii remote while the left shoulder roll motor is controlled with the roll motion. Slowly tilt and roll the wii remote for fine controls. Press the B button again to stop the control of Dynamixel. Press the A button to command DARwIn-OP to move to Stand position. Press the A button again to command DARwIn-OP to move to Sit position. Step 6 To exit out of the program, press control C on the command prompt ===== Demonstration ===== In this demonstration, I successfully compiled and execute the program described above {{ youtube>7HUNys41m6o?large }} ===== Final Words ===== This tutorial objective was to access the wii remote data and use it to control DARwIn-OP. The process of connecting a wiimote was explained as well as a client server model to send the data from the wii remote. Once the concepts were conveyed the reader could access data in the wii remote and use it for their project. Speculating future work derived from this tutorial, includes implementing a nunchuck to the wii and accessing its data. In the big picture, the problem of Wii remote control teleoperation can be solved with this tutorial.