How do I parse Arrow Keys from Telnet Client

I want to control servos of my wifi enabled robot using the arrow keys of my control node.
Currently I have the robot communicating with the node viva puTTY (telnet window) over a wifi connection. I can parse and control the robot with all other word commands I have however I wish to increment the speed slightly each time an arrow keys are pressed. I understand there is no ASCII code for the keys and they send two bytes instead of the standard one byte for other ASCII keys. Is there a method where I can achieve this ?

The code I am using to test looks like this

//-------Headers---------------------------------------------------------
#include <SPI.h>
#include <WiFi.h>
#include <Wire.h> 

//-------Varriables---------------------------------------------------------
char ssid[] = "TEST NETWORK";     //  Broadcasted SSID 
int status = WL_IDLE_STATUS;
WiFiServer server(23);            // Default Port 23
boolean alreadyConnected = false; // Flag to detect if already connected
char ch ='0';

//-------Setup---------------------------------------------------------
void setup() {
  Serial.begin(9600);   // Initialize Serial 9600 BAUD
  while (!Serial) {;}   // Wait for Serial to connect

  if (WiFi.status() == WL_NO_SHIELD) {           // If WiFi shield is not detected
    Serial.println("WiFi shield not present");   // Print error to Serial
    while(true);  }                               // Lock Up and wait for reset
  while ( status != WL_CONNECTED) { 
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);   
    status = WiFi.begin(ssid);                   // Start session for given SSID
    delay(10000);                }                // Wait 10 seconds for response
  server.begin(); 
  printWifiStatus(); 

 }

//-------Main Loop---------------------------------------------------------
void loop() {
  WiFiClient client = server.available();
  if (client) 
    {
    if (!alreadyConnected) 
    { client.flush(); 
      Serial.println("Laptop has connected to Arduino");
      client.println("Hello Laptop, From Rover!"); 
      alreadyConnected = true;  }
  
    
       
    while(client.connected())
    {  if (client.available()) 
        {   
            ch = client.read();             //Read Byte

            if((int)ch == 279165)
            {  Serial.print("UP ARROW RECIEVED");
            }
            Serial.print((int)ch);

        }
      }
      delay(1000);
      client.flush();
      ch = '0';
    }
}
            ch = client.read();             //Read Byte

            if((int)ch == 279165)

You're reading one byte and then check for a long integer constant?

You have to read byte after byte. If you're recognizing the start byte of the arrow key sequence, store that information in a status variable. In the next round check if the next character received is one the second characters in the arrow key sequences. If not reset the status variable to the default value.

Sorry reading the long integer was just something I was playing around with while trying to get this.
I tried treating the code as two seperate bytes earlier and it didnt work. But oddly treating the key as three bytes seems to work.

            ch = client.read();  

            if(ch==27)
            { ch=client.read();
              if(ch==91)
              { ch=client.read();
                if(ch==65)
                {  Serial.print("UP ARROW DETECTED");
                }
              }
            }

Im not sure why this is though

Because all data is transferred as bytes. This is not oddly, this is how everything works. The first byte (27) is the Escape character which initiates a special sequence.

Your code is not as robust as it might be though:

    {  if (client.available())

You're testing if one character is available at least but afterwards you're reading up to 3 characters without checking again if one is available. Because usually these characters are sent in the same packet in a telnet session, this will seldom crash your sketch but if the client side is not a human typing in on a keyboard (but a program automating things a bit), you might get a problem.

You're reading one byte and then check for a long integer constant?

Yeah, but there is a cast to int. :slight_smile:

@PaulS: you forgot the smiley. At least I hope it wasn't meant seriously.

@PaulS: you forgot the smiley. At least I hope it wasn't meant seriously.

Yeah, I forgot it.

Hi guys,

I'm working on a very similar project as to that outlined here. New to the Arduino world and enjoying it so far! :slight_smile:

I want to be able to control a number of servo's by sending keyboard keystrokes i.e. not having to press the enter key each time I want to increment servo position. Currently in the early stages of development; I've used the code supplied by MF4040 and adjusted it to my own needs. I've started with 2 servos, which increment/decrement their position on pressing the WASD keys (as shown in code below).

I'm connecting to the arduino via a telnet connection using PuTTY...

//-------Headers---------------------------------------------------------
#include <SPI.h>
#include <WiFi.h>
#include <Servo.h>

//-------Varriables---------------------------------------------------------
char ssid[] = "Addon";     //  Broadcasted SSID 
char pass[] = "mypass";
int status = WL_IDLE_STATUS;
WiFiServer server(23);            // Default Port 23
boolean alreadyConnected = false; // Flag to detect if already connected

Servo servo0;
Servo servo1;
Servo servo2;

int servo0pos, servo1pos = 90;
//-------Setup---------------------------------------------------------
void setup() 
{
  Serial.begin(9600);   // Initialize Serial 9600 BAUD
  Serial.println("'WiFi Servo Control WASD keys' loaded"); //To let me know whats loaded
  while (!Serial) {;}   // Wait for Serial to connect

// Check WiFi shield is connected
  if (WiFi.status() == WL_NO_SHIELD) 
  {           // If WiFi shield is not detected
    Serial.println("WiFi shield not present");   // Print error to Serial
    while(true);                                 // Lock Up and wait for reset
  } 
  
// Attempt to connect to Wifi network:
  while ( status != WL_CONNECTED) 
  { 
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);   
    status = WiFi.begin(ssid, pass);             // Start session for given SSID
    delay(10000);                                // Wait 10 seconds for response
  } 
  
  server.begin();             // Start the Server
  printWifiStatus();          // Print Connected Status
  
  servo0.write(servo0pos);    //set initial servo position
  servo1.write(servo1pos);
  servo0.attach(6);          //the pin for the servo control
  servo1.attach(8);
  
 }

//-------Main Loop---------------------------------------------------------
void loop() 
{
  WiFiClient client = server.available();   // Wait for a new client

  // When the client sends the first byte, say hello:
  if (client) 
  {
    if (!alreadyConnected) 
    {
      client.flush();          // clear out the input buffer:
      Serial.println("Laptop has connected to Arduino");
      client.println("Hello Laptop, From Tri-Track!"); 
      alreadyConnected = true;
    } 
  
  while (client.connected())
  {
  while (client.available())
  {
    if (client.available()) 
    {   
      char input = client.read();   // Read the bytes incoming from the client
      Serial.write(input);          // Echo the bytes to the server
      delay(2);  //slow looping to allow buffer to fill with next character
      
     switch (input) 
     {
    case 'w':
      servo0pos = servo0pos + 30;
      servo0.write(servo0pos);
      break;
    case 's':
      servo0pos = servo0pos - 30;
      servo0.write(servo0pos);
      break;
    case 'a':
      servo1pos = servo1pos + 30;
      servo1.write(servo1pos);
      break;
    case 'd':
      servo1pos = servo1pos - 30;
      servo1.write(servo1pos);
      break;
    default: 
      delay(5);
    }
  
  if (servo0pos > 180) //Let's servo position values stay in scope.
  {
    servo0pos = 180;
  }
  if (servo1pos > 180)
  {
    servo1pos = 180;
  }
  if (servo0pos < 0)
  {
    servo0pos = 0;
  }
  if (servo1pos < 0)
  {
    servo1pos = 0;
  }
   
   input = '0'; //clears user input
  }
  }
}
}
}
//-------Print WiFi Status Subroutine-------------------------------------------------
void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your WiFi shield's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

I know my code is less than robust! Still learning! :slight_smile:

I want to be able to change servo position on a single keystroke and not need to hit the Enter key each time

If anyone on this thread could give me a helping hand it would be much appreciated!

If anyone on this thread could give me a helping hand it would be much appreciated!

What do you need help with?

What do you need help with?

At the moment I can adjust servo position on entering W,A,S,D followed by a carriage return into the Telnet client. I want to be able to read if the keys are being pressed in real time and adjust servo position accordingly i.e. not have to hit 'Enter' after each keystroke.

I hope that clarifies?

edit: formatting

At the moment I can adjust servo position on entering W,A,S,D followed by a carriage return into the Telnet client.

"the Telnet client" doesn't tell us anything. You need to be more specific.

"the Telnet client" doesn't tell us anything. You need to be more specific.

I'll try my best...

Once the serial connection to my uno/wifi shield is up and I can see that the shield has connected to my network, I'm using PuTTY to set up a Telnet client to connect to my arduino's IP address on Port 23:

As you can see from the image, I open the client and can adjust the servos by entering either W,A,S or D.

  if (servo0pos > 180) //Let's servo position values stay in scope.
  {
    servo0pos = 180;
  }
  if (servo1pos > 180)
  {
    servo1pos = 180;
  }
  if (servo0pos < 0)
  {
    servo0pos = 0;
  }
  if (servo1pos < 0)
  {
    servo1pos = 0;
  }

It would probably be a good idea to constrain the values BEFORE writing them to the servos.

It would definitely be a good idea to use Tools + Auto Format to fix the indenting in your code.

It would definitely be a good idea to explain what the problem is. If the issue is that you need to hit the enter key after each letter, you need a different telnet client - one that automatically sends each letter as a packet, which might be hard to find, as most of the time, you do NOT want to send one letter per packet.

It would probably be a good idea to constrain the values BEFORE writing them to the servos.

It would definitely be a good idea to use Tools + Auto Format to fix the indenting in your code.

Ahh yes, that is a good idea. Thank you!

If the issue is that you need to hit the enter key after each letter, you need a different telnet client - one that automatically sends each letter as a packet

This is the issue. I'll see what I can find :confused:

Thanks for your help.

Edit: Done it!! For anyone browsing this thread in the future. PuTTY has a 'Local Line Editing' option under the 'Terminal' tab, select 'Force Off' :slight_smile: