| # Copyright (c) 2013 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import socket |
| |
| |
| RECV_CHUNK_SIZE = 1024 |
| MESSAGE_TERMINATOR = '\n' |
| |
| |
| class TouchbotComm: |
| """ Touchbot II Low-level communications module |
| |
| This class handles the low-level communications between the controller |
| and the robot. Touchbot II uses an Ethernet link to accept commands and |
| send responses to those commands. Here we set up a socket and initialize |
| the robot and through the member functions allow direct access to sending |
| whatever commands you want |
| |
| botcomm = TouchbotComm('192.168.0.1') |
| error_code, data = botcomm.SendCmd('freemode', -1) |
| ... |
| """ |
| def __init__(self, ip_addr, port): |
| """ Initiate contact with the TouchbotII over ethernet """ |
| self.soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
| self.soc.setsockopt(socket.SOL_SOCKET, socket.SO_DONTROUTE, 1) |
| |
| self.soc.connect((ip_addr, port)) |
| |
| self.SendCmd('version') # Print the version string |
| self.SendCmd('mode', 0) # Set the robot to PC communication mode |
| self.SendCmd('attach', 1) # Connect to the Touchbot (robot 1) |
| self.SendCmd('hp', 1, 10) # Turn on 'high power' mode |
| |
| def __del__(self): |
| """ Close the socket before cleaning up the object """ |
| self.soc.close() |
| |
| def SendCmd(self, cmd, *args): |
| """ Send a command to the TouchbotII |
| Commands are newline terminated strings of the format: |
| 'command arg0 arg1 ... argn' |
| eg: |
| 'mode 0' |
| Then wait for the robot's response and return that |
| """ |
| string_args = [str(arg) for arg in args] |
| cmd_string = ' '.join([cmd] + string_args) + MESSAGE_TERMINATOR |
| self.DisplayCmd(cmd_string) |
| self.soc.send(cmd_string) |
| return self.GetResponse() |
| |
| def GetResponse(self): |
| """ Listen on the socket for a response from the TouchbotII |
| parse the response and return it. Responses are of the format: |
| 'response_code data' |
| eg: For a command requesting the cartesian coordinates 'wherec' |
| '0 23.4 280.3 31.2 130.0 180.0 90.0' |
| """ |
| response = self.soc.recv(RECV_CHUNK_SIZE) |
| while response[-1] != MESSAGE_TERMINATOR: |
| response += self.soc.recv(RECV_CHUNK_SIZE) |
| |
| split_results = response.split(' ', 1) |
| raw_error_code = split_results[0] |
| num_results = len(split_results) |
| raw_data = split_results[1] if num_results == 2 else MESSAGE_TERMINATOR |
| error_code, data = int(raw_error_code), raw_data[:-1] |
| self.DisplayResponse(error_code, data) |
| |
| return error_code, data |
| |
| def DisplayCmd(self, cmd_string): |
| """ Print the name of a command to the console before sending it """ |
| print '[COMMAND]\t"%s"' % cmd_string[:-1] |
| |
| def DisplayResponse(self, error_code, data): |
| """ Display the message the robot returned and indicate any errors """ |
| success = (error_code == 0) |
| formatter = '[SUCCESS (%d)]\t%s' if success else '[ERROR(%d)]\t%s' |
| print formatter % (error_code, data) |