I tried something new this weekend and created a Unity integration with my C2 ergometer. I was following the approach that I wrote about a few months ago:
For my test-integration I used this script to generate some Bots and (a simulated) player. I then learned the basics of Unity to connect some sort of generic 3D application to show what the boats are doing.
I called the communication layer Fitznet – there’s Fitness and Network in there I guess. The protocol is based on Google Protobuf, I also created a small ZMQ Forwarder to keep the set up easy. Currently the whole thing is in an early development phase and I’m not sure if it will ever leave this state. But there’s some potential in there I think, perhaps if the right people are working on it…
I just ran into a very strange problem that almost caused me to reinstall my OS:
I installed QtCreator with a MinGW toolset fresh from the Qt-Homepage. Everything worked as expected and I created an empty Hello World project to test things out. From then on it got ugly: When starting the project QtCreator froze and I wasn’t able to delete the generated .exe file.
Epic Games recently announced that their Unreal Engine is available for free now. There are certain limitations when using it commercially, but these are far from being a limitation.
During the day I watched a lot of videos on the Epic Youtube-Channel, I also tried a few different things and discovered /r/unrealengine on reddit. I’m very fascinated by how complex, but well-thought the software is. I’ve rarely seen something big like that which also seems to simply work. I’m still working on getting a general overview to see the whole potential.
Perhaps it’d be worth it to remake DynRow in the Unreal Engine? There would be a lot of advantages I could see right now, like being able to support multiplatforms out of the box (Windows, Android, iOS, …) or having all these mighty tools in the background to help me developing it. Of course it would be perfect to have such high fidelity graphics available. What about a rowing simulation with VR support?
DynRow now records the users workout-data to a SQLite database during the session. This has several advantages:
Ghost Bot: This one is already implemented. There is a new Bot available which is able to read the SQLite data and apply it. The result is an opponent which rows exactly like the user rowed during a previous workout
Share workout: This is kind of related to the Ghost Bot. Users are now able to share their saved workouts with others. This means that it is possible to row against your rowing buddies or athletes you want to compete with
Better testing: I’m currently just creating data on the fly when no erg is connected. Though this is a good way to test the basic functionality it is always better to have real-life testing data. By being able to integrate previous workouts as a way to test it is now possible to easily reproduce certain bugs
Statistics: A workout application without the ability to generate complex statistics is not really exciting. By recording everything the user does during workout the foundation of generating statistics is now laid
One thing is also a bit related, but’ll need a bit more work to get it running: The ability to share the rowing data online during the workout. This would essentially allow to row against others in realtime over the internet. This feature is not planned as of yet, but it won’t be impossible to realize.
I fixed a lot of different issues with DynRow in the last days, but one feature stands out: I created Boomerang Bots. These bots are rowing with a constant pace until they get out of a certain range. Then they’ll reduce or increase speed to stay near the player.
This way it is possible to have different bots around the player for the entire exercise. This adresses one of the bigger problems I had with the available rowing software: I set up an opponent with a certain speed. In the beginning of the workout the opponent stayed near the boat and was a good motivation to keep going. Sometime during my workout however I was able to row faster than the bot or the bot was rowing away – I was basically rowing on my own for the rest of the time.
Boomerang Bots forgive smaller pauses the player does, they also keep up when the player has a good day and is rowing faster than expected.
So what’s next? I started refactoring the inner working and will do that primarily during the next days. I also want to make everything more user-friendly. Currently there’s no starting screen and the user needs to alter the code to set up his workout.
As part of the project a software developer should always “Eat his own dog foot”: test and use the application that is being developed. It’s important to know how your own product works and feels. Usually this is not a big deal, every now and then it is needed to run the code and test if everything works as expected. With DynRow it wasn’t that easy: I’m currently injured on my knee, so it’s not possible for me to get on the ergometer and just row away while DynRow runs in the background.
I was able to test the application with testing data – The player data did not come from the ergometer but from a generic input which generated a constant pace. However when I first sat down on my ergo a few days ago and actually tested the application, it was a whole other thing: Testing data did not show that for example certain statistics were too small to see them while in motion. Testing data also did not show that the currently implemented bots do not work very well when actually rowing against them.
What I did was to row with a very low intensity, just so my knee could handle it. I then put my phone beside me during the training session and everytime I noticed something I paused and noted it down. One of the first things I wrote down was that the application does not automatically Pause when the user interrupts his workout, so there’s that… I assembled a list of around 20 issues which I afterwards rethought and created about 15 Github issues from.
Now I have a bigger list of things that I could fix and implement. The first iteration worked good: I fixed some of the bigger issues yesterday and tried DynRow afterwards: It improved a lot and felt actually quite good to use. It’s not that good that I would actively promote it for others to use, but it’s making progress. Now I only have to heal up my knee so I can do some more intense testing (and also be able to get my fitness level up again).
The design of DynRow is quite simple and follows that of almost every game engine: There’s a loop running for the lifetime of the program. In every cycle the same steps are done:
Get the newest data from the Concept 2
Update the AI boats
Visualize the latest available data
Let’s just jump into these steps to get an overview:
Get data from the Concept 2: This is where PyRow is used. I created a static class called ErgStats which wraps around the PyRow-API. This way I’m not depending on PyRow everywhere in my application and I can easily swap it out if needed. A more object oriented way would be to create some sort of dependency injection here, that way I could more easily switch between generating test data and using the real data. Currently I implemented a quick hack where I used a try/catch when importing PyRow. If it fails to import I fall back to test data.
Update the AI: I created a PlayGround-class which holds a list of all the boats in the simulation. All boats get updated every cycle. The current logic implementation allows it to have different types of boats available, I just implemented a constant rowing boat and a very simple rubberband boat for now, but there’s potential to have more complex boats integrated.
Visualize everything: At first I used the TKInter Canvas because I wanted to use as less thirdparty software as possible. Python brings lot’s of stuff, so I thought it isn’t really needed to integrate more stuff from external repositories. My targeted hardware specification caused me to rethink this approach: I want DynRow to run on very basic hardware, at best it could be used on something simple like a Raspberry Pi. TKInter.Canvas, or at least the way I used it, is not very performant. After struggling a bit I added PyGame to the mix, which also provides some easy to use Gameloop-mechanics. My current implementation isn’t as optimized as it could be, but I’m quite happy with the resulting look and performance.
That’s almost everything you need to know. I wanted to keep the program as simple as possible, my primary focus was on creating a usable prototype as early as possible.
Recently I bought me a Concept 2 Rowing machine. I’ve been rowing a lot in my childhood and wanted a possibility to work out even if there’s not much time between work and other activities.
Another thing I looked forward too was the available SDK for the indoor rower. There’s a C-interface which allows to get all the data from the current rowing session. I also stumbled upon a Python lib called PyRow.
After some workouts where I tested different rowing software solutions like RowPro or the official Venue Racing application I found that there’s a lack in a sector where I expected the most: A training application which let’s me row against AI opponents that react realistically or according to my training goals.
It’s possible to record your rowing sessions in RowPro and replay them, it’s also possible to race against bots with a constant pace or which do specified intervals. But there’s no such thing as a bot which reacts to my heartrate or which tries to stay on my tail by sprinting before giving up. There’s a lot of potential left here, it would me a lot more motivating and effective to have advanced bots available to row against.
My idea was to create such a program – and born was DynRow. I used PyGame and PyRow to get all the needed data and display it in a userfriendly format. There’s now an application which displays the rowing boats from a birds-eye perspective. The player in the middle, all the other boats around the player. Other boats can be added as wanted, I currently have implemented a boat rowing with a constant pace and a somehow believable movement.
I’ll add more if I move further along, I also plan on going into more detail on some of the mechanics and designs involved. Feel free to get involved if you’re interested in rowing and have one of such ergometers available.
I’m using ZeroMQ both in CxxProf and at work extensively. Just recently I came across a bug which was only reproducible in a quite complex network scenario. The network implementation used ZeroMQ Publish/Subscribe sockets, so I wrote a component which recorded the network transfer and allowed me to replay it afterwards. By doing this I could completely ditch all the network components involved in the original bug and replay what was causing the bug on my desktop PC.
The target group of ZmqRecorder is probably not the biggest, but I guess that someone could put it to good use. It’s possible to improve the Player-implementation and allow to replay with more control like pausing or playing backwards, but it’s good for my usecase now.
I wrote about Continuous Integration before and even built a counter with which I’m able to monitor our CI environment at work. As CI is one of the greatest tool a software project could have, I wanted it for CxxProf too.
There are certain reasons speaking for a self-hosted CI:
Full control over the environment (OS, compiler, thirdparty, …)
Free choice of the CI tool (Jenkins of course!)
Customization options via plugins and configuration
Integration of continuous distribution
However there is one reason against it: I would need to rent a root server which costs a fortune. All for an open source project which is not designed to make any money. Another way would be to host it on one of my own machines, but it won’t have a lot of uptime then.
This is where hosted CI solutions come into play. A search findsdozensof them. I do not want to list all services I found, as it seems that there are new hosters coming up every day. I just want to list some disadvantages I found during my search:
Some cost a vast amount of money. These services are probably aimed at enterprises
Not all services support C++. There seems to be a good amount of Python and Ruby centric services out there
I did not find a service which is able to compile with Microsofts Visual Compiler
Continuous Distribution does not seem to be an important part for a lot of providers
A few services need a special config-file in the project root. This could have its own dis/advantages I think
After some research I stuck with Travis-CI and drone.io. I at first used codeship.io too, but it had a confusing UI and did not provide cmake, nor did it allow me to install it as part of the build process. So why these two services?
Has seemingly the most mature feature set
Supports compilation with clang++ (not only g++)
Fully integrated with Github
Full control: It is even possible to install new software using apt-get. It also allows to sudo certain commands
Neutral: No separate distribution options visible. However it is probably possible to create packages as part of the build and upload them anywhere
Negative: Uses an Ubuntu with 64bit. No 32bit machine available. Also no Windows environment
Negative: It is needed to add a configuration file to the code
Very slick UI, everything is easily findable
Fully integrated with Github
Full control: sudo and apt-get is usable as it is with travis
All the configuration is done online. That way the software stays untouched
Separate distribution area where configurable build artifacts are downloadable
Negative: Also uses a 64bit Ubuntu. No 32bit or Windows available
Both services are free for open source and provide notifications as soon as something fails. It seems as if drone.io is a bit better than Travis-CI, but the more mature appearance and its clang-support helped Travis staying on my list of solutions. It’s a bummer that both services leave out Windows, but as I said earlier there wasn’t a single service supporting it. Having reports for the Linux-builds is still a valuable tool, as it is not my main platform and I get continuous feedback that way.
I added an overview about the CI support of CxxProf in the wiki and onto the main Readme. Hope it stays green for a long time!