How to wirelessly control an ActivityBot from Python on a PC?
I'd like to wirelessly control an ActivityBot from Python on a PC.
I have a XBee S6B and also a WX ESP8266 WiFi Module + of course an ActivityBot. Haven't used these beauties for years now, and believe I only programmed a PAB through WiFi, but not controlled it.
Anyone knows how to connect from Python to one of these WiFi modules, and control it?
Of course I'd need to have a receiving program at the PAB side (C or Spin), but that should not be a problem once I know how to get the connection going. I found some material at https://learn.parallax.com/tutorials/language/propeller-c/parallax-wx-wi-fi-module-prop-c, but this is mainly about using web pages to control a robot, and only partially applicable to my use case.
In the end, I believe the hardest part will be for me to find the components in my storage boxes
FWIW, I quickly found the XBee S6B and WX ESP8266 modules I have, and decided to use the S6B. Main reason for that is that I used it 8 years ago to control an ActivityBot from iPad and I had already some C-code on the P1 side, basically a collectively developed program, as part of this open project: https://forums.parallax.com/discussion/153214/open-propeller-project-1-ipad-to-activitybot/p1
I found the below Python skeleton to use on the PC side.
Now I'm almost able to control the ActivityBot through a consumer grade EEG-headband. If I get this to work more consistently, I'll post a figure-8 video of it
Due to the many components involved (my brain => EEG-headband => BlueTooth => phone/phone app => WiFi => PC/Python+TensorFlow => WiFi => ActivityBot), there are some lags, am working on measuring and trying to minimize them. Error handling would also be good to have...
That seemed like a worthwhile project that you linked to but too bad it died around the time I started using the Propeller.
I am not familiar with Python but I like that it's similar to BASIC.
I grew up with BASIC but PASCAL taught me how to write a proper program; I loved PASCAL but it's not used anymore.
Yeah, Python is a bit similar to BASIC, Spin and partially also Pascal as it it kind of verbose. What I love with Python is that you don't need any curly braces or similar as in C, just like in Spin it's all about indentation. Actually I started to use Python in practice just last month as I started to teach a univesity course in it. Best way to learn a subject is to have to teach it
Related to the brain-controlled bot, I've made some serious progress the last hours, if all goes well I'll upload a video after a few days or so.
The nice thing about Python it's good on a Mac or a Windows PC. The while loop needs its own thread or it will make the UI unresponsive, I don't know how far you have got with python over the last month or so but this is a real basic example of the beginnings of a GUI. I don't know if I can help much but if I think I have something to offer the conversation I will chime in.
The example receives a string from the Prop and responds by replying with "Hello World", this example uses ASCII both directions
@Unsoundcode Thx a lot! I was going to try to implement the Prop messaging back to Python, but you now saved me at least a few hours of time!
I am a little new with python also, the example in the last post is a little crude, I know we can do much better but it gives us a few things to think about if we wanted to create a GUI.
A couple of things to think about with regards to the socket, this set up is dedicated to just one wifi device defined by the IP (XCTU MY) and port # of the XBee, to point at a different wifi device means changing IP (XCTU MY) and perhaps the port # in your python script
With a slightly modified script you can make the PC a server that would be able to accept connections from any one of several devices with a destination address that matched you PC (XCTU DL) and matching port number.
The IP and port # can also be changed over serial with a Propeller script if you wanted.
Lastly the python script you are currently using will block at the receiving line of code if there is no data this causes the program to hang.
That can be avoided with a timeout or removing blocking altogether
Modifying the first example we have something that functions pretty well now. This example works on Mac and Windows and sends/receives ASCII char or string of ASCII chars, for now the transmit side from the PC appends a newline but that can easily be removed. The next step would be to decide which commands you wanted to send to the Activity Bot and start creating functions associated to buttons. Maybe add an entry for XBee IP and port selection also.
EDIT : there should be the s.close() instruction just before the break
On the Prop side, what code would this Python script communicate with? Is it C code from the Learn (SimpleIDE) library or .spin code? Is there a simple example?
This is the C code, from SimpleIde library, that I used in 2014 sending data to my iPad. xBee initialization obviously needs to be done before. Let me know if you need that one as well, in that case I'll clean up my code before posting it here. The below code sends the Ping distance in cm in two separate bytes, this is because Ping distance can be well over 255, around 373 centimeters if I remember correctly.
Thanks. I can use this... I just wanted the simplest code, which I may translate to .spin2!
Hi banjo, you spoke of error checking and I looked at that a little today. The main scenarios I was thinking of were being unable to establish communication and loss of communication during usage. The first case was fairly straightforward to deal with and I have included it with a sample today. The second case uses the same try/exception handler as the first basically but I wondered if the inclusion of some kind of heartbeat between devices might be a good thing, I'm not sure what to think about that. This sample also puts the status messages into a dictionary and cleans things up some. The biggest change in my opinion was the way 2 variables and an object are passed in and out of a second thread. That's new to me and though it works fine I wondered if you had any experience or thoughts on that topic.
dgately, I am thinking that this program will communicate with any of the Parallax WiFi units and the microcontrollers that connect to those WiFi units. All the microcontrollers have to worry about are the serial communications the WiFI is completely transparent as far as they are concerned. As it is now we just pass ASCII chars back and forth for testing, the characters are not processed in any way, by removing encode and decode we can just as easily transmit/receive byte packets.
Hi @Unsoundcode Thx again for your efforts! Both of your programs seem to work well, I'm just struggling to understand how to communicate properly between the Prop and the program. I'm not sure if it's the encoding that is throwing me off, as when sending Ping distance back, it seems to only go up to 90 127 cm. This is when printing unencoded data to the terminal window, like this:
Initially I also had understanding issues when sending data to the Prop, as I got decimal 10 regardless of what I send. But reading your post above, I understood I just needed to remove the newline character.
Warning, offtopic rant:
Damn forum software which stalls the whole Chrome tab every ~20 seconds, for ~1 minute at a time, makes it close impossible to use. This did not happen before to me, but I've understood some others have experienced same problem. It also puts a heavy load on my laptop --> high temp --> screen starts to flicker as introduced by M$ in their "Flickergate" Surface Pro 4 computers.
By adding these I'm able to print the low and high bytes of the word
~~ int_val = int.from_bytes(my_var, "big")
print("int_val = ", int_val)~~
Hi banjo, this will read and display 16bit/32bit values
If this is the point we are at then we should start to give thought to a simple protocol so that the data can be defined in a packet. If you are wanting to do some tests using byte data you should be ok for now just separate your data with a small interval of time.
If I get the time I will try and set something up on a Prop, I also want to look into passing objects as function arguments on the python side.
Hi banjo, I noticed the socket does not behave as I expected in particular the use of blocking/nonblocking/timeout.
Nonblocking and timeout were giving too many exceptions, I was able to catch the exceptions and ignore them but I did not think that was the best way to handle it. So I went back to blocking in the secondary thread, which is fine for the receive method, and I moved sendall into a function in the main thread.
Another thing I noticed is the socket will time out if the receive is idle for approximately 60 seconds or more. This is something we can handle in the Propeller code by sending a heartbeat signal at regular intervals.
The following two snippets are to test PC to Propeller using Python and SimpleIDE with a XBee wifi connected just as it is in the Parallax tutorial, that is D0 and D1 connected to P9 and P8 respectively. This is really basic stuff that uses ASCII characters for testing.
For a hobby project I think it is getting very close to being useful and it is at a stage where most beginners could modify it for their projects.
EDIT I should mention that the Prop code is Run With Terminal
@Unsoundcode Great! Also thx for creating a short snippet for the Prop side, the one I have is kind of a monster as I have lots of AT-commands to configure the xBee, and stuff to steer the ActivityBot, originally from an iPad.
Related to your thoughts about a simple protocol, I wonder if it would be worthwhile to take a look at the xBee API mode before.
For my part, I have a tight schedule for this project overall (controlling an ActivityBot from an EEG-headband). As I now, thx to you, have what I need on the Prop and Python side for a prototype, I'm focusing on the Machine Learning part and trying to understand why the excellent training results are not reflected in a real situation. I have a hypothesis on that, and am now working on it.
@Unsoundcode, thanks, as well! Simplifying WiFi comms to ASCII makes it easy to debug on the prop side. I've been looking for a simple example like this. I actually translated the prop side C code to spin2 and am running it on a P2.
BTW: Using a Parallax WiFi module instead of an XBee, I had to change the port from 9750 to 23.
@banjo To be honest because of your schedule I would stick to ASCII text for now while you concentrate on developing the rest of your project. A protocol can be put in place at a later time, if you really want to work with binary data packets perhaps start with a fixed packet length for each instruction that should work well in this situation. It also seems to me that AT commands add an extra level of complexity that might not be needed, I configure the XBee using a FTDI 3.3v cable and XCTU software then I can forget about that side of things and move on to something else, it all depends on where your research is focused. If I get the time I will try for a better Propeller example to go with the Python code it's working but everything is up for improvement. I'm glad you understood the heartbeat concept it was an important piece of the puzzle and something I did not quite expect at first.
@dgately that's awesome thanks so much for the feedback, I have actually been looking at putting the Python side into it's own class, I think I can do that but it is pushing my Python abilities to a different level. I have already got a version of what is here that accepts host and port as user input.
This post is for those who might be new to using WiFi modules and want to experiment a little. Again there is nothing drastic changing here it's all fairly simple stuff, the aim was to emulate something similar to the official Parallax WiFi demo which echoes characters that have been typed into the terminal. This needs an additional line of code in the python program that can be removed or commented when not needed.
The Propeller code is not serious stuff either but it does demonstrate two things which are a progression from the previous examples and of interest to a beginner, the first displays the route each character travels to get to be displayed in the terminal and the second which might go unnoticed at first glance is the use of the tilde character as a header that is used in a logical decision inside the Propeller program.
@Unsoundcode I'm actually trying to get 2 Parallax WiFi modules to 'talk' to each other, in ASCII. And, doing that in spin2 (or spin for a P1, as well). I have no problem getting a JOIN to work (to my local network), but a CONNECT to either another WiFI module or to my MacBook gets an error... The following code:
@dgately hi, I am by no means a network guru I think I learnt as much as anyone in this last exercise. Having said that there is another snippet that I have that acts as a PC server to one or more clients, does that sound like a road you would go down. I'll look into what's involved, I do have two WiFi modules and a Mac and PC I can try the WiFi hardware and software with.
I find this thread very interesting. I have dabbled in tkinter for some of my projects, PC python GUI connection to a P1 and a P2 using the serial method.
The Python socket was a new discovery for me. I will have to revisit some of my older code and see if using Python socket would be appropriate.
@banjo, I am also interested in machine learning, I hope you will share some findings. Interested in seeing what sort of algorithm you come up with.
@Rsadeika hi, I too have had a few good experiences using serial communication talking to a Prop or an Arduino via Python, its a very quick and easy way to develop a reasonable custom GUI. My last project was a "mini" logger that saved data samples to a CSV file, I did that because I thought it performed a little better than PLX-DAQ and was cross platform.
I am new to sockets and I think the multi client server would be a great project, but it is not quite as straightforward as what we have been doing here so I have to give up on that one.
@banjo I am also interested in your progress, keep us posted.
@banjo @dgately @Rsadeika hi guys,
dgately got me thinking about this but you all might find it interesting to play around with.
This is a server example straight out of the Python socket documentation. It looks similar but differs from the previous example in several ways, the host is no longer filled in with the WiFi modules IP, the HOST='0.0.0.0' allows for connection from any device on the network provided the device has a destination IP the same as the PC the server is on. This server will only communicate with one module at a time, when one socket closes the next can have access. The Propeller no longer needs to transmit a 'heartbeat' signal
My test network is two XBees and one PC or Mac but it will work just as well using one wifi module or PC to PC.
To get this set up to work in a reasonable way I modified two of the XBee settings, the first is the one I mentioned above and that was to set the destination address of both XBees (DL in XCTU config.) to point at my PC's IP. The second setting I adjusted was TCP client connection time out (TM in XCTU config.), what this does is send data to the PC, receives data from the PC and then closes the socket connection when the timeout value is reached. I arbitrarily set the time out at 5mS, this was short enough to quickly transmit and receive a small data packet then close and allow the next XBee to connect and do the same. I don't know for sure but probably other wifi units have the time out feature.
To use this with two wifi clients needs a little thought on how it should be synchronized. I would think it needs some kind of ACK from the server for each time a client sent data, some kind of addressing to know where the data is from where it is going etc. A way to go yet but I'm sure I'll play around with this some more.
For this I transmit '#' and receive the same back
My improved brain-controlled ActivityBot is still some weeks/months away (due to having finalized a Master's Thesis here in between). To take baby steps, I've worked on controlling a very simple Pong-game by using an EEG-headset and recognizing eye blinks, this was published yesterday: https://docs.edgeimpulse.com/experts/eeg-data-control-games.
After improving the ML (Machine Learning) part, I'm now continuing with next EEG & ML-project. Here the user can communicate he is hungry, very hungry, thirsty, needs a bathroom break etc. just by wearing the EEG-headset and trying to move left or right hand. This part is already kind of working (the final version is quite similar as the mockup picture below), and I'm now implementing the possibility to also write short sentences by selecting words or letters from a word/alphabet "carousel".
The next project after that will be to control an ActivityBot with better accuracy than earlier this year, the goal being to perform a figure-8.