Emotions are important when expressing oneself as 60% of communication is expressed through the emotion found in one’s face. This guide will show how to implement emotion display on a screen with ROS.
The first step is to download the module pygame using terminal.
sudo apt-get install python-pygame
The next step is to open up a text editor and begin with importing pygame. Next you would want to create a loop to create a continuous screen.
#! /usr/bin/env python import pygame screen = pygame.display.set_mode((640, 480)) running = 1 while running: event = pygame.event.poll() if event.type == pygame.QUIT: running = 0 screen.fill((0, 0, 0)) pygame.display.flip()
This allows for a continuous screen to be displayed on the screen.
Although there is currently a screen, there is nothing that is being displayed, so now is the time to add the 7 faces: neutral, happy, surprise, anger, disgust, fear, and sad.
With the 7 faces above, there is a certain gradual factor based on the confidence of that face that allows each face to revert to the neutral face. An example will be provided of the anger face to show how the gradual factor is included. Another important aspect of displaying the face is to utilize an eye coordinate location. Since sympathy also relies on the location of the eyes, it is included into the eyes. When drawing the eyes and mouths, you can utilize this API to check how to draw each face. The program utilizes an array to store values or probabilities of each emotion.
#draws the eyes pygame.draw.circle(screen, (0, 0, 0), (255 + eyecoordx, 250 + eyecoordy), 15) pygame.draw.circle(screen, (0, 0, 0), (355 + eyecoordx, 250 + eyecoordy), 15) pygame.draw.polygon(screen, (255, 255, 255), [(270 + eyecoordx, 235 + (30 * emotionamts[0]) + eyecoordy), (270 + eyecoordx, 235 + eyecoordy), (270 - (30 * emotionamts[0]) + eyecoordx, 235 + eyecoordy)], 0) pygame.draw.polygon(screen, (255, 255, 255), [(340 + eyecoordx, 235 + eyecoordy), (340 + eyecoordx, 235 + (30 * emotionamts[0]) + eyecoordy), (340 + (30 * emotionamts[0]) + eyecoordx, 235 + eyecoordy)], 0) #draws the mouth pygame.draw.lines(screen, (0, 0, 0), False, [(240, 355 + int(20*emotionamts[0])), (305, 355), (370, 355+int(20*emotionamts[0]))], 5)
The next step would be to integrate ROS into the program or Robot Operating System. Since there is not much information to be published. There will be no need to use a publisher. A subscriber will be needed. First, the subscriber would need to collect which emotion is currently expressed and the probability of the emotion.
import rospy import std_msgs.msg import String def callback(data): text = str(data.data) index = text.index(" ",0,len(text)) emotion = text[:index]; for x in xrange(0, 7): if(emotions[x] == emotion): global wanted wanted = float(text[index+1:]) global direcpos global pos direcpos = x if(pos == -1): pos = x emotionamts[pos] = wanted def listener(): rospy.init_node('emotiondisplay', anonymous=True) rospy.Subscriber("emotiondisplay2", String, callback) rospy.spin()
After integrating ROS into the program, multithreading is needed to collect information as a subscriber as well as continuously printing out to a screen. To multithread, you need to import the threading module and the time module. With these modules, we can sleep a thread to check for possible messages from the publisher. To ensure that threads don’t switch during the process, the use of a lock is necessary.
import thread import time import threading lock = threading.Lock() def callback(data): with lock: text = str(data.data) index = text.index(" ",0,len(text)) emotion = text[:index]; for x in xrange(0, 7): if(emotions[x] == emotion): global wanted wanted = float(text[index+1:]) global direcpos global pos direcpos = x if(pos == -1): pos = x emotionamts[pos] = wanted def func(delay): done = False first = True while(not done): with lock: display() time.sleep(delay) def main(): try: thread.start_new_thread(func, (.01,)) listener() except Exception, e: print str(e)
This code allows for both threads, displaying the screen and collecting data from the publisher, to run simultaneously. The func method is called by thread.start_new_thread method is given a parameter of .01 seconds in which is the delay time between each print of display unless the lock of callback prevents it.