Accept optional input at runtime - python

currently I am writing a robot operating system (ros) node in python. I want to create a while loop which accepts user input on the one hand but is able to continue if no user input is available.
The idea of the following snippet is, that this python-script offers always 'start' or 'stop'. Another node is listening what string gets published. The user should be able to type in 0 or 1 at runtime to toggle the flag.
Here is my python code:
def main():
pub = rospy.Publisher('/start_stop', String, queue_size=10)
rospy.init_node('start_stop', anonymous = True);
rate=rospy.Rate(10) # 10hz
pubStr = "Start"
while not rospy.is_shutdown():
try:
input = raw_input()
if input == "0":
pubStr = "Stop"
elif input == "1":
pubStr = "Start"
except:
rospy.sleep(0.1)
rospy.loginfo(pubStr)
pub.publish(pubStr)
rate.sleep()
if __name__ == '__main__':
main();

In case you don't find a way to do this directly in Python, an easy solution would be to move the user input to another node:
The first node (let's call it "user input node") looks basically like the code you posted, but publishes directly the value of input to a topic /user_input.
The second node ("start/stop node") publishes the "Start"/"Stop" in a loop, depending on the flag. This flag is set by a callback listening to /user_input.
This way, the start/stop node always publishes depending on the user input, without waiting for new input, while the user can always change the flag by sending a new value via the user input node.
This solution would be easy to implement but has the downside of an additional node in your setup.

Related

Why I need to type exit command multiple times to leave console app?

I am writing a console application which should close every time user type 'exit'. It works only when starting function is called once, otherwise I have to type 'exit' multiple times.
For example: I run the application, type "1", "recipe", "exit" and it works fine. When I type "1", [enter], "2", "exit" - i need to type "exit" one more time... or more (depending on function call times).
Starting function
def start():
running = 'on'
while running == 'on':
recipes.show_recipes()
recipe_choice = input("...")
if recipe_choice == "exit":
running = 'off'
else:
try:
recipes.show_recipes(int(recipe_choice))
except IndexError:
print("...")
start()
except ValueError:
print("...")
start()
response = input("...")
if response == "recipe":
#opening recipe .pdf file
openrecipe(list(list(recipes.recipes.values())[int(recipe_choice)-1].values())[2], shell=True)
start()
elif response == "exit":
running = 'off'
else:
start()
Run program
start()
I suppose that solution is simple but I can't figure out why my application behave like that. I would like to close program any moment I type "exit" in console.
You don't need to call start() over and over - once your program reaches the end of one of it's if clauses, it should start back at the head of the while loop. Otherwise, you're initiating new loops that you have to exit out of manually.
Your function is calling itself recursively, each time pushing a new frame to the call stack and starting a new loop. So if you end up piling say three recursive calls, the first "exit" will exit the last loop, the function execution finishes, the top frame is popped from the stack and the control goes back to the previous stack, so you're back to the second loop, etc (lather, rinse, repeat...)
Recursion is a useful tool when you have to deal with arbitrary nested data structures (trees etc) but it really doesn't belong here - it's both useless (a simple iteration is all you need) and harmful (it keeps on piling on frame after frame eating memory for no good reason and - as you discovered - makes flow control much harder than it has to be).

Passing variables through multiple functions python

So I'm trying to make a function that prompts the user for an option, and depending on which option it does something to the information.
Optionone() basically asks the user for information for a single contact, and every time this contact is filled out it creates a list in a list full of the diff contacts.
In optionthree() I am trying to ask a user for a contact they want to display. So once they type in the name of the contact, the code should display the entire list consisting of the contact's information (name, address, phone, email).
I've excluded the other options that are irrelevant to this problem.
contact = []
def optionone():
contactinfo = []
name = str(input("Name: "))
address = str(input("Address: "))
phone = str(input("Phone: "))
email = str(input("Email: "))
contactinfo.append(name)
contactinfo.append(address)
contactinfo.append(phone)
contactinfo.append(email)
contact.append(contactinfo)
contactinfo = []
This is the optionthree function.
def optionthree(contactinfo):
search = input("Name of contact: ")
if search in contactinfo:
print("This is what I'm trying to figure out")
else:
print("There is no contact with that name in your address book.")
return contactinfo
And the main menu function
def menu():
option = int(input("""
Menu Options:
1. Add new contact
2. Display address book
3. Search for contact
4. Modify contact
5. Delete contact
6. Exit
Choose an option: """))
if option == 1:
optionone()
elif option == 3:
info = optionthree(contactinfo)
main()
Right now, when I run this in terminal, it tells me that I'm referencing to the variable contactinfo before it is assigned. The whole concept of parameters and passing variables through functions is very confusing for me; what is wrong in this code?
you use contactinfo in the main function, but didn't define it in the main function. I notice you define a global variable "contact". Not sure if it is the same variable
It looks like you are attempting to reference contactinfo before it gets assigned any values. If you need to have executed option 1 before executing option 3, then you may want option 3 to first check if contactinfo exists. If it doesn't exist, I would suggest writing that line as the following:
info = optionthree(optionone())
Here at Stack Overflow, we handle one problem at a time. In this case, the immediate problem is the undefined variable. Please handle the info look-up in a separate posting, if you still can't figure it out.
I'm going to get rid of extra information for illustration. It's a good programming technique: take little steps. First, we're going to get a name only into the list and be able to find it. You have almost everything hooked up.
The basic principle to remember is that each function has its own "name space" (directory of variables and values). Functions communicate with each other through the parameter list and return values. Yes, there are global variables, too. For now, don't use them.
The purpose of option_one is to add a name to the info list, and make the change available to the main program. You forgot the last part: you have to send back the updated list when you're done:
def option_one(contact_list):
name = str(input("Name: "))
contact_list.append(name)
print("OPT 1 contact_list", contact_list) # trace what you do for debugging purposes.
return contact_list
def menu():
# Menu text omitted
master_list = []
if option == 1:
master_list = option_one(master_list)
print("MAIN ", master_list)
elif option == 3:
info = option_three(master_list)
menu()
Make your main program "own" the master list -- the option functions merely get a copy, do their "thing", and return the updated list (if needed). The main program has to initialize that list, master_list, and hand it off to each chosen function.
Each function has its own little world: what it got from the calling program, the local variables it creates, and what it hands back when it's done. Each routine can call that contact list by whatever local name it chooses; I've called it contact_list (as you did, but with "Pythonic" punctuation).
Output:
Choose an option: 1
Name: Mark
OPT 1 contact_list ['Mark']
MAIN ['Mark']

Python, pyserial program for communicating with Zaber TLSR300B

I'm still new here so I apologize if I make any mistakes or if my question is not specific enough, please correct me! I'm working on a program for controlling two Zaber TLSR300B linear motion tracks in a laser lab via a serial connection. I have no problems communicating with them using pyserial, I've been able to write and read data no problem. My questions is more about how to structure my program to achieve the desired functionality (I have very little formal programming training).
What I would like the program to do is provide a number of methods which allow the user to send commands to the tracks which then return what the track responds. However, I do not want the program to hang while checking for responses, so I can't just write methods with write commands followed by a read command. For some commands, the tracks respond right away (return ID, return current position, etc.) but for others the tracks respond once the requested action has been performed (move to location, move home, etc.). For example, if a move_absolute command is sent the track will move to the desired position and then send a reply with its new position. Also, the tracks can be moved manually with a physical knob, which causes them to continuously send their current position as they move (this is why I need to continuously read the serial data).
I've attached code below where I implement a thread to read data from the serial port when there is data to read and put it in a queue. Then another thread takes items from the queue and handles them, modifying the appropriate values of the ZaberTLSR300B objects which store the current attributes of each track. The methods at the bottom are some of the methods I'd like the user to be able to call. They simply write commands to the serial port, and the responses are then picked up and handled by the continuously running read thread.
The main problem I run into is that those methods will have no knowledge of what the track responds so they can't return the reply, and I can't think of a way to fix this. So I can't write something like:
newPosition = TrackManager.move_absolute(track 1, 5000)
or
currentPosition = TrackManager.return_current_position(track 2)
which is in the end what I want the user to be able to do (also since I'd like to implement some sort of GUI on top of this in the future).
Anyways, am I going about this in the right way? Or is there a cleaner way to implement this sort of behavior? I am willing to completely rewrite everything if need be!
Thanks, and let me know if anything is unclear.
Zaber TLSR300B Manual (if needed): http://www.zaber.com/wiki/Manuals/T-LSR
CODE:
TRACK MANAGER CLASS
import serial
import threading
import struct
import time
from collections import deque
from zaberdevices import ZaberTLSR300B
class TrackManager:
def __init__(self):
self.serial = serial.Serial("COM5",9600,8,'N',timeout=None)
self.track1 = ZaberTLSR300B(1, self.serial)
self.track2 = ZaberTLSR300B(2, self.serial)
self.trackList = [self.track1, self.track2]
self.serialQueue = deque()
self.runThread1 = True
self.thread1 = threading.Thread(target=self.workerThread1)
self.thread1.start()
self.runThread2 = True
self.thread2 = threading.Thread(target=self.workerThread2)
self.thread2.start()
def workerThread1(self):
while self.runThread1 == True:
while self.serial.inWaiting() != 0:
bytes = self.serial.read(6)
self.serialQueue.append(struct.unpack('<BBl', bytes))
def workerThread2(self):
while self.runThread2 == True:
try:
reply = self.serialQueue.popleft()
for track in self.trackList:
if track.trackNumber == reply[0]:
self.handleReply(track, reply)
except:
continue
def handleReply(self, track, reply):
if reply[1] == 10:
track.update_position(reply[2])
elif reply[1] == 16:
track.storedPositions[address] = track.position
elif reply[1] == 20:
track.update_position(reply[2])
elif reply[1] == 21:
track.update_position(reply[2])
elif reply[1] == 60:
track.update_position(reply[2])
def move_absolute(self, trackNumber, position):
packet = struct.pack("<BBl", trackNumber, 20, position)
self.serial.write(packet)
def move_relative(self, trackNumber, distance):
packet = struct.pack("<BBl", trackNumber, 21, distance)
self.serial.write(packet)
def return_current_position(self, trackNumber):
packet = struct.pack("<BBl", trackNumber, 60, 0)
self.serial.write(packet)
def return_stored_position(self, trackNumber, address):
packet = struct.pack("<BBl", trackNumber, 17, address)
self.serial.write(packet)
def store_current_position(self, trackNumber, address):
packet = struct.pack("<BBl", trackNumber, 16, address)
self.serial.write(packet)
zaberdevices.py ZaberTLSR300B class
class ZaberTLSR300B:
def __init__(self, trackNumber, serial):
self.trackNumber = trackNumber
self.serial = serial
self.position = None
self.storedPositions = []
def update_position(self, position):
self.position = position
There is an option on the controllers to disable all of the replies that don't immediately follow a command. You can do this by enabling bits 0 and 5 of the Device Mode setting. These bits correspond to 'disable auto-replies' and 'disable manual move tracking'. Bit 11 is enabled by default, so the combined value to enable these bits is 2081.
My recommendation would be to disable these extra responses so that you can then rely on the predictable and reliable command->response model. For example to move a device you would send the move command, but never look for a response from that command. To check whether the movement has completed, you could either use the Return Current Position command and read the position response, or use the Return Status (Cmd_54) command to check whether the device is busy (i.e. moving) or idle.
So, the way I went about doing this when a multithreaded application needed to share the same data was implementing my own "locker". Basically your threads would call this ChekWrite method, it would return true or false, if true, it would set the lock to true, then use the shared resource by calling another method inside of it, after complete, it would set the lock to false. If not, it would wait some time, then try again. The check write would be its own class. You can look online for some Multithreading lock examples and you should be golden. Also, this is all based on my interpretation of your code and description above... I like pictures.
Custom Locks Threading python
/n/r
EDIT
My fault. When your ListenerThread obtains data and needs to write it to the response stack, it will need to ask permission. So, it will call a method, CheckWrite, which is static, This method will take in the data as a parameter and return a bit or boolean. Inside this function, it will check to see if it is in use, we will call it Locked. If it is locked, it will return false, and your listener will wait some time and then try again. If it is unlocked. It will set it to locked, then will proceed in writing to the response stack. Once it is finished, it will unlock the method. On your response stack, you will have to implement the same functionality. It slipped my mind when i created the graphic. Your main program, or whatever wants to read the data, will need to ask permission to read from, lock the Locker value and proceed to read the data and clear it. Also, you can get rid of the stack altogether and have a method inside that write method that goes ahead and conducts logic on the data. I would separate it out, but to each their own.

Create a raw input with commands inside a Python script

I'm trying to implement a small script to manage a localhost with an FTP connection in Python from the command line and using the appropriate "ftplib" module. I would like to create a sort of raw input for the user but with some commands already setup.
I try to explain better:
Once I have created the FTP connection and login connection been successfully completed through username and password, i would show a sort of "bash shell" with the possibility to use the most famous UNIX commands ( for example cd and ls respectively to move in a directory and show file/folders in the current path ).
For example i could do this:
> cd "path inside localhost"
thus showing directories or:
> ls
to show all files and directories in that particular path. I've no idea how to implement this so i ask you some advices.
I thank you so much in advance for the help.
It sounds like the command line interface is that part that you are asking about. One good way to map user inputs to commands is to use a dictionary and the fact that in python you can run a reference to a function by putting () after it's names. Here's a quick example showing you what I mean
def firstThing(): # this could be your 'cd' task
print 'ran first task'
def secondThing(): # another task you would want to run
print 'ran second task'
def showCommands(): # a task to show available commands
print functionDict.keys()
# a dictionary mapping commands to functions (you could do the same with classes)
functionDict = {'f1': firstThing, 'f2': secondThing, 'help': showCommands}
# the actual function that gets the input
def main():
cont = True
while(cont):
selection = raw_input('enter your selection ')
if selection == 'q': # quick and dirty way to give the user a way out
cont = False
elif selection in functionDict.keys():
functionDict[selection]()
else:
print 'my friend, you do not know me. enter help to see VALID commands'
if __name__ == '__main__':
main()

Return to code after function runs

I'm making a text-based game and need an application-wide command line that's able to be pulled up at any text entry. My plan was to have the commands contained within a module, and execute command(), which would then allow the user to enter a command (or get a list) that is then run (contained within the same module). This didn't work because I need a way to return to where the user was. Is there anyway to return to where the user was before they entered command mode, or is there a better way to do this?
This was my idea:
import commands
def something():
print "a question"
action = raw_input("> ")
if action == "command":
commands.commands()
elif "something else" in action:
do something
else:
error.error(1)
something()
Which then went to commands.py:
def commands():
print "Enter a command, help for a list, blah blah blah."
command = raw_input("$ ")
if command == "bag":
bag()
elif command == "other":
other()
def bag():
print "Action listing things in bag"
The problem is returning where the user left off.
What you need is a main game loop:
while game.is_running:
command = get_user_input()
user_do(command)
update_world()
This will repeat the three lines of code inside the while loop for as long as game.is_running is True. First, you get the user input. Next, you act on it. Finally, you perform any other updates your game needs, like moving or spawning monsters. At this point, it loops back and asks the user for another command.
Update: here is a working example:
# In commands.py:
def bag():
print 'bag'
def other():
print 'other'
def unrecognized():
print 'unknown command'
# In main.py:
import commands
def user_input():
print 'a question'
return raw_input('>')
def user_do(command):
# get the matching command out of commands, or pass back
# the unrecognized function if it's not found
action = getattr(commands, command, commands.unrecognized)
action()
is_running = True
while is_running:
command = user_input()
if command == 'quit':
is_running = False
else:
user_do(command)
In this example, I've cheated and am relying on the user input commands being identical to the name of the functions to be called. In user_do, the getattr call compares the string the user has input with the contents of the command module, returning the function of the same name if one exists, or the fallback function unrecognized if it doesn't. action will now either hold the command function or unrecognized.
If you don't want to have your user commands so tightly bound to the actual functions themselves, you can use a dict as a branching construct (or dispatch) instead of having a lot of if / elif / else statements:
# Modified main.py
import commands
COMMAND_DISPATCH = {
'bag': commands.bag,
'sack': commands.bag,
'other': commands.other,
# ...
}
# ...
def user_do(command):
action = COMMAND_DISPATCH.get(command, commands.unrecognized)
action()
In this example, rather than look up the functions in the commands module, we look them up in COMMAND_DISPATCH instead.
One more bit of advice: pretty soon you'll want to look at parsing the user input into more than just a single command. For this example, let's assume you want to be able to accept input of the form "command ... ". You can extend the user_input function to take care of this:
def user_input():
print 'a question'
user_input = raw_input('>').split(' ')
command = user_input[0]
arguments = user_input[1:]
return command, arguments
So if you enter 'foo bar baz', this would return the tuple ('foo', ['bar', 'baz']). Next we update the main loop to deal with the arguments.
while is_running:
# use tuple unpacking to split into command, argument pairs
command, arguments = user_input()
if command == 'quit':
is_running = False
else:
user_do(command, arguments)
Then make sure we pass them to the command:
def user_do(command, arguments):
action = COMMAND_DISPATCH.get(command, commands.unrecognized)
action(arguments)
And finally, we modify the commands to accept and handle the arguments:
def bag(arguments):
for argument in arguments:
print 'bagged ', argument
For a text adventure, you'll want a more substantial parser, something that deals with command object, command object preposition subject, and possibly even command adjective object ....
You should research "python finite state machine". It is pretty much exactly what you want.
Charming Python: Using state machines
Finite-state machine
wiki.python.org/moin/FiniteStateMachine
What is a state machine?
An overly accurate description of a state machine is that it is a
directed graph, consisting of a set of nodes and a corresponding set
of transition functions. The machine "runs" by responding to a series
of events. Each event is in the domain of the transition function
belonging to the "current" node, where the function's range is a
subset of the nodes. The function returns the "next" (perhaps the
same) node. At least one of these nodes must be an end-state. When an
end-state is reached, the machine stops.
When to use a state machine ...
Start in an initial state.
Read a line of input.
Depending on the input and the current state, either transition to a new state or process the line as appropriate for the current state.
Similar to what #MatthewTrevor suggested in his answer, you would have a main loop, and pass a "state" context to the first entry point call (start or intro or whatever). That call can change the state context to point at something else. When control reaches back to the main loop again and it checks the state, it will run the new state.

Categories