Keyboard Commands
Keyboard commands give the user the ability to modify variables during a flight test. The actions each key performs is completely customizable and can trigger anything from just adjusting a PID constant, to executing complex functions.
To get the basic idea of how the function works, here is a flow chart of the process and an example trigger:
Reading the Keyboard Input
We use the select() function for a non-blocking method to read the keyboard input from the STDIN file descriptor in linux. The function below is what we currently use to read the keyboard. (The function was provided by Dr. Phillip Jones):
- 1. First we need to establish the base functions that we will use to read the key input (code found in vrpn.cpp):
////////////////////////////////////////////////// // kbhit // // Descption: used select to do a non blocking // // read of stdin. // // // ////////////////////////////////////////////////// int kbhit() { struct timeval tv; fd_set fds; tv.tv_sec = 0; tv.tv_usec = 0; FD_ZERO(&fds); FD_SET(STDIN_FILENO, &fds); //STDIN_FILENO is 0 select(STDIN_FILENO+1, &fds, NULL, NULL, &tv); return FD_ISSET(STDIN_FILENO, &fds); }
- Then we can make it non-blocking code with the following:
////////////////////////////////////////////////// // nonblock // // Descption: Turn off connoical mode so the // // user does not need to hit enter after // // pressing a key // // // ////////////////////////////////////////////////// void nonblock(int state) { struct termios ttystate; //get the terminal state tcgetattr(STDIN_FILENO, &ttystate); if (state==1) { //turn off canonical mode ttystate.c_lflag &= ~ICANON; //minimum of number input read. ttystate.c_cc[VMIN] = 1; } else if (state==0) { //turn on canonical mode ttystate.c_lflag |= ICANON; } //set the terminal attributes. tcsetattr(STDIN_FILENO, TCSANOW, &ttystate); }
- 2. Reading the Keypress (code in vrpn.cpp):
nonblock(1); usleep(1); i = kbhit(); //keyboard hit (state change) if (i!=0) //If state has changed, read and record key value { keystroke_now = fgetc(stdin); if (keystroke_now == 'q') i=1; else{ i=0; } } //END IF readKeyboard(); //Uses key value input to trigger actions
- All this code is doing is checking the
STDINfile descriptor for a state change, if it has then read that change and record the key value that was pressed.
- All this code is doing is checking the
- 3. Using the Key value to trigger actions (code in vrpn.cpp):
void readKeyboard() { //========Reads Keystrokes from Keyboard========== nonblock(1); if (keystroke_now != keystroke_prev) { //If the keyvalue has changed (Debouncing safety) /* if (keystroke_now == 'w') { yPositionDesired1 -= 0.2; cout << "New Y Setpoint: " << yPositionDesired1 << endl; } else if (keystroke_now == 's') { yPositionDesired1 += 0.2; cout << "New Y Setpoint: " << yPositionDesired1 << endl; } else if (keystroke_now == 'a') { xPositionDesired1 -= 0.2; cout << "New X Setpoint: " << xPositionDesired1 << endl; } else if (keystroke_now == 'd') { xPositionDesired1 += 0.2; cout << "New X Setpoint: " << xPositionDesired1 << endl; } else if (keystroke_now == 'r') { zPositionDesired1 += 0.2; cout << "New Z Setpoint: " << zPositionDesired1 << endl; } else if (keystroke_now == 'f') { zPositionDesired1 -= 0.2; cout << "New Z Setpoint: " << zPositionDesired1 << endl; } */ //Commented out above inputs if (keystroke_now == '1') { yawDesired1 += 45.0; cout << "New Yaw Setpoint: " << yawDesired1 << endl; } else if (keystroke_now == '2') { yawDesired1 -= 45.0; cout << "New Yaw Setpoint: " << yawDesired1 << endl; } else if (keystroke_now == 'k') { cflieCopter1->m_enumFlightMode = GROUNDED_MODE; if(cflieCopter2){ cflieCopter2->m_enumFlightMode = GROUNDED_MODE;} if(cflieCopter3){ cflieCopter3->m_enumFlightMode = GROUNDED_MODE;} if(cflieCopter4){ cflieCopter4->m_enumFlightMode = GROUNDED_MODE;} } else if (keystroke_now == 'e') { cflieCopter1->m_enumFlightMode = LANDING_MODE; if(cflieCopter2){ cflieCopter2->m_enumFlightMode = LANDING_MODE;} if(cflieCopter3){ cflieCopter3->m_enumFlightMode = LANDING_MODE;} if(cflieCopter4){ cflieCopter4->m_enumFlightMode = LANDING_MODE;} handMode = 0; // landingMode ^= 1; // mirrorMode = 0; cout << "Landing Mode Enabled" << endl; } else if (keystroke_now == 'm') { cflieCopter1->m_enumFlightMode = MIRROR_MODE; if(cflieCopter2){ cflieCopter2->m_enumFlightMode = MIRROR_MODE;} if(cflieCopter3){ cflieCopter3->m_enumFlightMode = MIRROR_MODE;} if(cflieCopter4){ cflieCopter4->m_enumFlightMode = MIRROR_MODE;} // mirrorMode ^= 1; cout << "Mirror Mode Enabled" << endl; } else if (keystroke_now == 'h') { handMode = 1; cout << "Hand Mode Enabled" << endl; } else if (keystroke_now == 't') { cflieCopter1->m_enumFlightMode = TAKEOFF_MODE; // takeOff1 = 1; takeOffTime1 = cflieCopter1->currentTime() - initTime1; } else if (keystroke_now == 'y') { cflieCopter2->m_enumFlightMode = TAKEOFF_MODE; // takeOff2 = 1; takeOffTime2 = cflieCopter2->currentTime() - initTime2; } else if (keystroke_now == 'u') { cflieCopter3->m_enumFlightMode = TAKEOFF_MODE; // takeOff3 = 1; takeOffTime3 = cflieCopter3->currentTime() - initTime3; } else if (keystroke_now == 'i') { cflieCopter4->m_enumFlightMode = TAKEOFF_MODE; // takeOff4 = 1; takeOffTime4 = cflieCopter4->currentTime() - initTime4; } // else if (keystroke_now == '`') { // tcp_server_ON ^= 1; // } else if (keystroke_now == '1') { // tcp_client_ON ^= 1; // } // else if (keystroke_now == 'o') { // flap = 1; // } // else if (keystroke_now == 'l') { // flap = 0; // } keystroke_prev = keystroke_now; } nonblock(0); }//END readKeyboard()
- This is just a bunch of 'if' checks that activate if a certain key has been pressed.
- So we can see that the first 8 options just simply add or subtract a constant value to a variable in the code whenever that key is pressed.
- The options after that are what trigger different Flight Modes, telling the Crazyflie to do things like Take-Off, or to Fly in Formation, or to Land. These are more complex functions and can change the behavior of the entire swarm! See the Flight Modes page for more information on this.
- This is just a bunch of 'if' checks that activate if a certain key has been pressed.
