Голосовое управление манипулятором

манипулятор
Joris Laurenssen взял старый манипулятор и используя телефон на базе Android и Arduino, реализовал его голосовое управление!

У манипулятора имеется свой собственный управляющий контроллер, который соединяется через порт DB-25. Сначала, Joris выяснил, что контроллер посылает команды через параллельный порт, затем он подключил Arduino и сделал так, чтобы он считывал значения от контроллера и пересылал их в последовательный порт. Это позволило ему установить довольно простой ASCII-код, используемый, для управления движением манипулятора (всего восемь наборов команд).
Далее, он написал простой скетч для Arduino который стал управлять манипулятором вместо родного контроллера.

Затем, Joris реализовал распознавание голосовых команд, которые выдавали управляющие сигналы манипулятору. Для этого, он использовал функцию распознавания речи своего телефона на базе Android (использовал Scripting Layer for Android (SL4A)) и скрипт на Python-е, чтобы интерпретировать команды и выдавать их в последовательный порт для Arduino.

демонстрационное видео — Robotic arm speech control (Joris даёт команды на голландском языке, но он наложил комментарии на английском, так что всё понятно):


скетч управления манипулятором (считывает команды с последовательного порта и выставляет соответствующие биты на «параллельном соединении»)
const int numberOfChars = 40;
const int millisToWait = 1000;

byte command[numberOfChars] = {};

// define parallel port pins as arduino I/O pins
const int nStrobe = 2;
const int data_0 = 3; // -+
const int data_1 = 4; //  |
const int data_2 = 5; //  |
const int data_3 = 6; //  |- the 8 data pins
const int data_4 = 7; //  |
const int data_5 = 8; //  |
const int data_6 = 9; //  |
const int data_7 = 10;// -+
const int nAck = 11;
const int busy = 12;

const int strobeWait = 20;   // time in microseconds for strobe


void setup() {
  Serial.begin(9600); //serial connection with copmuter. 9600 bps

  pinMode(nStrobe, OUTPUT);      // is active LOW
  digitalWrite(nStrobe, HIGH);   // set HIGH
  pinMode(data_0, OUTPUT);
  pinMode(data_1, OUTPUT);
  pinMode(data_2, OUTPUT);
  pinMode(data_3, OUTPUT);
  pinMode(data_4, OUTPUT);
  pinMode(data_5, OUTPUT);
  pinMode(data_6, OUTPUT);
  pinMode(data_7, OUTPUT);

  pinMode(nAck, INPUT);     // is active LOW
  pinMode(busy, INPUT);  
}

void loop() {
  while (Serial.available()<=0){}

  int bytes_read = 0 ;

  while (bytes_read < numberOfChars){
    if (Serial.available() > 0){
      command[bytes_read] = Serial.read();
      bytes_read ++;
    }
  }

  for(int n = 0; n < numberOfChars; n++){
    Serial.write(command[n]);
  }

  printMessage();

  Serial.println("Action complete");
}

void printByte(byte inByte) {
  while(digitalRead(busy) == HIGH) {
    // wait until robotic arm can receive data
  }

  int b0 = bitRead(inByte, 0); // -+
  int b1 = bitRead(inByte, 1); //  |
  int b2 = bitRead(inByte, 2); //  |
  int b3 = bitRead(inByte, 3); //  |- convert the byte to write to 8 seperate intergers
  int b4 = bitRead(inByte, 4); //  |
  int b5 = bitRead(inByte, 5); //  |
  int b6 = bitRead(inByte, 6); //  |
  int b7 = bitRead(inByte, 7); // -+

  digitalWrite(data_0, b0); // -+
  digitalWrite(data_1, b1); //  |
  digitalWrite(data_2, b2); //  |
  digitalWrite(data_3, b3); //  |- write the 8 intergers to the data outputs
  digitalWrite(data_4, b4); //  |
  digitalWrite(data_5, b5); //  |
  digitalWrite(data_6, b6); //  |
  digitalWrite(data_7, b7); // -+

  digitalWrite(nStrobe, LOW);       // strobe nStrobe to input data bits
  delayMicroseconds(strobeWait);
  digitalWrite(nStrobe, HIGH);

  while(digitalRead(busy) == HIGH) {
    Serial.print("*");
  } 
}

void printMessage() {
  for(int cursorPosition = 0; cursorPosition < numberOfChars; cursorPosition++) {
    byte character = command[cursorPosition];
    Serial.print(character);

    printByte(character);
    delay(1);
  }
  printByte(10); // new line
  printByte(13); // carriage return
  Serial.println("done"); //notify computer that the action is complete
}


robotArmControl.py
# This program is used on an android device using the SL4A (scripting layer
# for android) package. It uses voice recognicion as input, and it sends the
# command to the computer attached to the robotic arm using the telnet protocol
# 
# Joris Laurenssen

import android
import sys
import telnetlib
import time
import re

program = "python sendToArduino.py"

command = "" # make an variable to store the command
move_value = 500

# This function makes a "sound  hash" of the text
def soundex(text, len=4):
   digits = "01230420002566012723044802"
   sndx = ""
   fc = ""
   text = text.upper()

   # replace groups of letters
   reps = {"QU":"KW","SCH":"SEE","KS":"XX","KX":"XX","KC":"KK","CK":"KK","DT":"TT","TD":"TT","CH":"GG","SZ":"SS","IJ":"YY"}

   for i,j in reps.iteritems():
      text = text.replace(i,j)
   
   for c in text:
      if c.isalpha():  # only if c is in the alphabet
         if not fc: fc = c  # remember first letter
         # convert the letter to a number in the alphabet, and look up
         # that position int the digits string
         d = digits[ord(c)-ord("A")]
         # remove duplicates
         if not sndx or (d != sndx[-1]):
            sndx += d
   sndx = fc + sndx[1:]
   sndx = sndx.replace("0","") # remove all the 0's (a, e, h, i, o, u, j, y)
   return (sndx + (len * "0"))[:len]


def inSoundex(text, sound_hash):
   text = text.split(" ")
   for word in text:
      if soundex(word) == sound_hash:
         print soundex(word)
         return True


# this function uses speech recognicion to make the command
def transcribeCommand():
   global command # we use the global command variable
   global move_value
   global continue_program
   raw_command = droid.recognizeSpeech("Spreek het commando?", None, None)
   print("You said: " + raw_command[1]) # verification

   # Check the results for keywords, and make the command string
   # used soundhashes:
   #  open
   #   O160
   #  dicht
   #   D230
   #  rechts
   #   R232
   #  links
   #   L680
   #  omhoog
   #   O620
   #  omlaag
   #   O652
   #  pols
   #   P520
   #  elleboog
   #   E512
   #  schouder
   #   S370
   #  basis
   #   B220
   #  precisie
   #   P722
   #  stop
   #   S310
   
   if inSoundex(raw_command[1], "O160"): # open
      command = "O"
   elif inSoundex(raw_command[1], "D230"): # dicht
      command = "C"
   elif inSoundex(raw_command[1], "P520"): # pols
      if inSoundex(raw_command[1], "R232"): # rechts
         command = "M0,0,0," + str(move_value) + "," + str(move_value) + ",0"
      elif inSoundex(raw_command[1], "L680"): # links
         command = "M0,0,0," + str(0-move_value) + "," + str(0-move_value) + ",0"
      elif inSoundex(raw_command[1], "O620"): # omhoog
         command = "M0,0,0," + str(0-move_value) + "," + str(move_value) + ",0"
      elif inSoundex(raw_command[1], "O652"): # omlaag
         command = "M0,0,0," + str(move_value) + "," + str(0-move_value) + ",0"
   elif inSoundex(raw_command[1], "E512"): # elleboog
      if inSoundex(raw_command[1], "O620"): # omhoog
         command = "M0,0," + str(move_value) + ",0,0,0"
      elif inSoundex(raw_command[1], "O652"): # omlaag
         command = "M0,0," + str(0-move_value) + ",0,0,0"
   elif inSoundex(raw_command[1], "S370") or inSoundex(raw_command[1], "S372"): # schouder
      if inSoundex(raw_command[1], "O620"): # omhoog
         command = "M0," + str(move_value) + ",0,0,0,0"
      elif inSoundex(raw_command[1], "O652"): # omlaag
         command = "M0," + str(0-move_value) + ",0,0,0,0"
   elif inSoundex(raw_command[1], "B220"): # basis
      if inSoundex(raw_command[1], "L680"): # links
         command = "M" + str(move_value) + ",0,0,0,0,0"
      elif inSoundex(raw_command[1], "R232"): # rechts
         command = "M" + str(0-move_value) + ",0,0,0,0,0"
   elif inSoundex(raw_command[1], "P722"): # precisie
      # get a numbet out of the string using a regex
      number = re.findall("[0-9]+", raw_command[1])
      if number != []:
         droid.makeToast(number[0]
)
         move_value = int(number[0])
   elif inSoundex(raw_command[1], "S310"): # stop
      continue_program = False
      

   if command == "": # if the command is empty, it did not recognice a case
      transcribeCommand() # repeat the voice recognicion proces
      
   droid.makeToast(command) # command verification

# this function connects to the computer using telnet
def telnetConnect():
   tn.read_until("login: ")
   tn.write(user + "\n")
   if password:
      tn.read_until("Password: ", 1)
      tn.write(password + "\n")
   droid.makeToast("Verbonden met de computer.") # notify that there is a connection

# send the command using telnet
def telnetWrite():
   global command
   print("python pws.py " + command + "\n") # verification
   tn.write(program + " " + command + "\n")
   print "written command to computer" # verification
   command = "" # clear the command for the next command


def telnetEnd(): # logout and print the telnet log
   tn.write("exit\n")
   print tn.read_all()
   droid.makeToast("De verbinding is gesloten.")


droid = android.Android() # make androiod instance

# ask for the ip adress of the computer
HOST = droid.dialogGetInput('IP', 'Wat is het ip adres van de computer?').result

# the move value is the step widht of the robotic arm
# move_value = int(droid.dialogGetInput('Stapgrootte', 'Wat is de stapgrootte?').result)

# telnet account and password
user = "android"
password = "android"

continue_program = True

tn = telnetlib.Telnet(HOST) # make telnet instance

telnetConnect() # connect to telnet

# while the user wants to continue, listen and send commands
while continue_program == True:
   transcribeCommand()
   telnetWrite()
   print continue_program

telnetEnd()


toArduino.py
import sys
import serial
ser = serial.Serial('/dev/ttyUSB0', 9600)

command = sys.argv[1]

while len(command) < 40:
   command = command + " "
if command > 40:
   command = command[0:41]

print command

ser.open()
if ser.isOpen():
   ser.write(command)


Ссылки:
Robot-arm speech control
Scripting Layer for Android
LPT (IEEE 1284)

По теме:
Клешня
Теперь клешня и по Bluetooth
Самые разные манипуляторы из Makeblock
uArm — открытый проект манипулятора под управлением Arduino
Roboticarm V2 — манипулятор изготовленный при помощи 3D-печати
  • +2
  • 28 марта 2012, 07:33
  • admin

Комментарии (1)

RSS свернуть / развернуть
+
0
Мда, дядьке этому оператор switch явно неведомен. Но все равно здорово получилось
avatar

Radiolok

  • 29 марта 2012, 19:04

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.