Closed dwalton76 closed 8 years ago
@rhempel feel free to assign this to me. I created the ticket in case anyone else is interested in working on this with me.
I'm actually working with Laurens on the python port. We're nearly there... Some trouble with r/w speed. It's patched in the development branch.
Cool. Laurens and I were trading emails in Jan when I was working on this, he was very helpful. I got it somewhat working but it still needed some fine tuning. My branch is https://github.com/dwalton76/ev3dev-lang-python/tree/gyro
feel free to grab anything from there that you like. Laurens said he had a much better algorithm in the works so I stopped working on this until he got that published.
I have a program for the gyroboy in progress. However, I have been having trouble getting the loop time down as well. What kind of loop time are you able to get? I am at 20-25ms. Hoping to get it down below 10ms though. It seems like I was getting this 1+ years ago the last time I was doing a balancing robot in ev3dev. Basically, each sysfs read/write is 3 to 4ms, which is way too long. If we could get it down to 1ms, it would be ok. It depends on if there is something in python that can be changed or if the seek and read/write syscalls just actually take that long.
It's also interesting to me that the first iteration of the loop takes much longer. Here are my function call times in ms for the first iteration.
GT: 0
time: 0
GG: 14
GM: 12
EQ: 1
cntrl: 8
CHK: 1
sleep: 2
Then for a later iteration...
GT: 0
time: 0
GG: 4
GM: 8
EQ: 1
cntrl: 7
CHK: 1
sleep: 0
GG
is reading the gyro sensor value. GM
reads the motor positions of 2 motors and cntrl
writes the duty_cycle_sp of 2 motors.
I've included the patch from @antonvh that removes the extra absolute path lookup, which, by the way, no longer seems to be in the develop
branch (did @rhempel force push?)
Interesting. I was using python3, however times are better in python2.
Python 2.7.9 (default, Mar 1 2015, 13:52:09)
[GCC 4.9.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import timeit
>>> timeit.repeat('f.seek(0); f.read()', 'f = open("/sys/class/tacho-motor/motor0/position", "r+")', number=1000)
[1.2495520114898682, 1.2299458980560303, 1.206686019897461]
Python 3.4.2 (default, Oct 8 2014, 14:47:30)
[GCC 4.9.1] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import timeit
>>> timeit.repeat('f.seek(0); f.read()', 'f = open("/sys/class/tacho-motor/motor0/position", "r+")', number=1000)
[3.638115724999807, 3.6730630889996974, 3.7583993859989278]
hmm... I implemented the change I suggested for python3 in #155, but I'm not really seeing any changes in performance.
GT: 0
time: 1
GG: 3
GM: 6
EQ: 1
cntrl: 7
CHK: 0
sleep: 2
No @rhempel did not pull in that patch yet (he thinks)
First iteration is longer because it sets up the caching subsystem - after that the reads/writes go through already open file handles.
No @rhempel did not pull in that patch yet (he thinks)
I think @dlech was pointing out that the PR was merged but the commits are no longer in the develop branch. That likely means that someone force-pushed while their working HEAD was behind the remote.
I've made a gyroboy program that does not use ev3dev-lang-python. I got the loop time down to about 15ms, so there is some overhead in ev3dev-lang-python that might be able to be shaved off, but the really just might be the best we can do with python and sysfs.
Lauren's has a newer version of his balancing algorithm and he wrote it in Python. I made a class based version of it for ev3dev. I am out of town for work right now but will send a pull request this weekend when I get home. He has his cycle time at 10ms
I did a python version of the balancer here: https://github.com/antonvh/segway It's forked from the original by @laurensvalk here: https://github.com/laurensvalk/segway
I used ev3dev and with my patch (https://github.com/antonvh/ev3dev-lang-python/commit/abdcae4b3fbf0902a7c515041885fb21ec13cf10) I get loop times of around 16-17ms which is enough to balance.
Laurens' version is without ev3dev and directly reads files. He's getting loop times of around 11ms. I think the ev3dev overhead is still too large. A few lines of python shouldn't make milliseconds of difference. I wonder where that comes from.
I also did a BrickPi version: https://github.com/antonvh/segway/tree/brickpi
On the Pi I get loop times of 10ms with ev3dev. But the BrickPi is acting up. It's all shaky and it feels like 'updateMotorsAndSensors()' is called too often by the driver. I have to investigate that some more, but I ran out of time.
Actually, my loop takes about 6 ms. (I spend the remaining 4ms busy waiting.)
@dlech Feel free to try out this code. It is tuned for BALANC3R, but not much tuning of the gain values should be required for GyroBoy.
I think that ev3dev-lang-python overhead involves a couple of function calls (which are expensive in python), and a dictionary lookup for the cached file handle (even more expensive). This requires some testing, but I don't see how we could get rid of any of those.
@ddemidov Would storing the file handle as a Device() property speed things up? This would maybe avoid function calls as Motors etc are subclassed?
On Thu, Mar 31, 2016 at 9:23 AM Denis Demidov notifications@github.com wrote:
I think that ev3dev-lang-python overhead involves a couple of function calls (which are expensive in python), and a dictionary lookup for the cached file handle (even more expensive). This requires some testing, but I don't see how we could get rid of any of those.
— You are receiving this because you were mentioned. Reply to this email directly or view it on GitHub https://github.com/rhempel/ev3dev-lang-python/issues/130#issuecomment-203794226
Best way to find out is to run some tests (which I am not able to do now). The implementation should be careful not to leak file handles though.
On the Pi I get loop times of 10ms with ev3dev. But the BrickPi is acting up. It's all shaky and it feels like 'updateMotorsAndSensors()' is called too often by the driver. I have to investigate that some more, but I ran out of time.
updateMotorsAndSensors
is actually only being called every 10ms in the current BrickPi drivers. I am increasing it to 4ms in the next kernel release for better motor control. I don't understand how calling updateMotorsAndSensors
"too often" could be a bad thing.
To void the cache lookup, maybe we should consider setting instance variables for the file handles (one per attribute) - we can easily create these programmatically based on the language spec. If the instance variable is None
then we need to open the file.
I should probably build one of these balancing robots myself - for science :-)
I went as bare metal as I could (avoiding function calls, using low-level file io, etc.) and got the loop time down below 10ms and it seems to be working fairly well. It's not nearly as elegant of a program though.
I did try @laurensvalk's program with the GyroBoy. It works ok, but I found it to be "all shaky" like @antonvh's BrickPi version. I didn't try tuning it yet though.
Gyroboy has much bigger wheels. Instead of tuning, you could put on the small wheels. Tuning essentially scales for this.
The center of mass is a bit different as well, but this should have a smaller effect.
I might provide values for Gyroboy too at one point; I just need to rebuild it.
This one actually runs ev3dev. Kudos to @antonvh for printing the line-following tiles.
I submitted a pull request for what I have. https://github.com/rhempel/ev3dev-lang-python/pull/157
The bulk of the code is @laurensvalk 's, I just ported it to a class and added support to use a remote control.
@dwalton, I will be rewriting the attribute access in ev3dev-lang-python
to take advantage of some significant speed improvements. See ev3dev-lang-python
https://github.com/rhempel/ev3dev-lang-python/issues/155
This is great! When the speed improvement becomes part of the latest image release, I'll update my Segway code to work with ev3dev-lang-python instead of directly reading files.
My feeling is timing jitter is a worse problem for this type of control than the loop rate. If someone could manage to get precise 50 Hz or even 20Hz or so that should be plenty. Just a feeling. BTW
I made Gyroboy and it worked with some ev3dev Python code I got sent by dlech, but I had to tune the coefs a bit to "stiffen" the control; I also had to mod it for the right wheel size. Both took less than 1 hour. I made Balancer with the wheels I ripped off Gyroboy, and Lauren's Lego code and it worked straight off.
My request would be to implement some mechanism in ev3dev that allows python threads to be triggered at fairly precise intervals, that are reproducible whatever the OS version of the day. My intuition says that any simple PID code coeficients will be very sensitive to the time slice and the timing precision.
Edmund
I got @dwalton76's code working with the latest version of core.py
in the feature-remove-attribute-cache
branch - the BALAC3R is a bit jittery, but that may be because we may need to tighten up the loop speed, or because the jitter on loop time is too high.
The main thing is that it "just works" which is awesome. I have just got it balancing today - tomorrow is for getting the remote control and then maybe the line follower working.
I am super excited about the new Python binding, and have learned a bit more about Python than I knew before.
Special thanks to @laurensvalk for the BALANC3R instructions and to @dwalton76 for providing updated code.
By working together and bouncing ideas off each other, we have managed to create a much better binding that what we started with.
cool :) FYI the pull request code has remote control support already...hadn't done anything with line following though.
@edmundronald :
My feeling is timing jitter is a worse problem for this type of control than the loop rate. If someone could manage to get precise 50 Hz or even 20Hz or so that should be plenty
There is some interesting discussions and some attempts at this in #324.
I will retune the code for 20 ms (50 Hz) so we have some more space for other things. But even at 10 ms (100 Hz) jitter isn't really an issue. Tuning seems to be more critical. I'll see if it helps to account for battery level.
@rhempel :
The main thing is that it "just works" which is awesome. I have just got it balancing today - tomorrow is for getting the remote control and then maybe the line follower working.
I've not yet checked @dwalton76 's modifications, but there should be a "steering" and "speed" variable that you can modify without worrying about the balancing algorithm.
Then line following becomes just two lines:
speed = 10 #Or more, depending on how tight the corners are
steering = (RelectedLightValue - Threshold)*ScaleFactor
This is essentially a proportional controller where ScaleFactor controls the tightness of the turn. Depending on the light sensor value mode you choose (raw or percentage), you'll want to start with a ScaleFactor such that steering always ends up approximately in the range [-20, 20] and then tune it for slightly more or less tight turns.
@dwalton76 I see you currently have a function for remote control:
def make_move(self, button)
Perhaps it would be nice to have a slightly more general purpose function like this:
def make_move(self, speed, steering)
Then line following and remote control in the main loop can use this to interface with balancing.
Right now @dwalton's code does not have the light sensor built in, just the remote control. I may pull in your line following code while I'm at FIRST in St Louis this week
@rhempel any objections to me approving my own pull request (or if you want to do it, either way is fine)? Then someone can add line follower support on top of what I've already done.
@laurensvalk I need to look at it some more but I think make_move() is expected to have only that one button arg so that it can play nicely with the remote-control hook.
@dwalton, go ahead and approve your PR for the demo code changes
Can someone volunteer to help me get this,code on my EV3? I had a version running Gyroboy- am ok with Linux but don't know about Git.
btw I think timing jitter is equivalent roughly to multiplicative noise (rather than additive). I have a background (PhD) in neural net control.
@edmundronald roughly you want to do
PR merged
@dwalton thank you very much. I will do this and come back.
Edmund
@dwalton76 Done.
(Ran the update process specced here http://www.ev3dev.org/support/ Prefixed sudo to your instructions, and ran the rest. )
What now? Where is the latest compatible code for Balancer, how do I run it?
Edmund
@dwalton76 I tried running a file in the demo dir, not much luck.
robot@ev3dev:~/ev3dev-lang-python/demo$ ls -l
total 24
-rwxr-xr-x 1 robot robot 4582 Apr 27 23:12 auto-drive.py
-rwxr-xr-x 1 robot robot 844 Apr 27 23:12 BALANC3R
drwxr-xr-x 2 robot robot 4096 Apr 27 23:12 lego_official_projects
-rw-r--r-- 1 robot robot 226 Apr 27 23:12 README.rst
-rwxr-xr-x 1 robot robot 3787 Apr 27 23:12 remote-control.py
robot@ev3dev:~/ev3dev-lang-python/demo$ python BALANC3R
2016-04-27 23:48:41,169 INFO: Starting BALANC3R
2016-04-27 23:48:41,443 ERROR: unsupported operand type(s) for +: 'NoneType' and 'str'
Traceback (most recent call last):
File "build/bdist.linux-armv5tejl/egg/ev3dev/GyroBalancer.py", line 281, in main
touchSensorValueRaw = open(self.touch._path + "/value0", "rb")
TypeError: unsupported operand type(s) for +: 'NoneType' and 'str'
Traceback (most recent call last):
File "BALANC3R", line 28, in
@laurens or @antonvanh - do you have the balancer code with the line follower as well?
@rhempel : Yes, I just uploaded the line following example to my github just for you. I'm guessing it is for the FIRST festival so I'll keep it short. You need to:
Also, you just tagged another Github user called Laurens.
Or if you use Git, this is all you need to do, as I believe it maintains the executable settings:
@edmundronald in your case, if you don't need line following just yet, run the other program, so just do:
@laurensvalk I followed your instructions. The program segway.py seems to run, except it doesn't do anything apart from exiting when I press the touch sensor. Here is the console output.
robot@ev3dev:~/segway/ev3/ev3dev/python$ ./segway.py
-----------------------------------
Calibrating...
GyroOffset: 0.07
-----------------------------------
GO!
-----------------------------------
Loop time: 10.436174568965518 ms
-----------------------------------
STOP
-----------------------------------
robot@ev3dev:~/segway/ev3/ev3dev/python$
@laurensvalk I've checked that the motors are on A and D, and are seen by Brickman, the values change when I twist the wheels. And I extracted the SD card and ran your Balanc3r-Remote-control project with great success, it balances. It's just the Python version which doesn't move the wheels. Any ideas?
btw, I also ran the demo in https://github.com/rhempel/ev3dev-lang-python.git and it runs errorfree, now that I have added the touch sensor to the hardware, but it also doesn't move the motors.
Edmund
my guess is a kernel version/ev3dev-lang-python version mismatch. there have been breaking changes to the motor drivers, so if they don't match, motors don't work.
Also, I would suggest https://help.github.com/categories/writing-on-github/
if you put a "code fence" around your terminal output, it makes it much easier to read.
^ this is the start of a code fence
code goes here
v this is the end of the code fence
@dlech What should I do at this point? Until "hello world" runs, I am slavishly following instructions. I have now scanned through the netiquette link. Here anyway is a codefence test:
Ceci n'est pas du code
I wish there were backticks on my french keypboard
Buvez de ce whisky que le patron juge fameux
You can edit your previous post so we can read it. :wink:
Also, what kernel are you running on your EV3 (output of uname -r
)?
@dlech Edited. Now, why didn't I think of that by myself? :)
robot@ev3dev:~$ uname -r
3.16.7-ckt26-10-ev3dev-ev3
robot@ev3dev:~$
Nice article here on these robotos: http://robotsquare.com/2014/07/01/tutorial-ev3-self-balancing-robot/
The author has an older blog post with a RobotC implemenation of the software: http://robotsquare.com/2012/02/13/tutorial-segway-with-robotc/
I started porting that to python here: https://github.com/dwalton76/ev3dev-lang-python/tree/gyro/demo/lego_official_projects
but do not have things working yet.