Friday, July 20, 2018

A Whirlpool/jacuzzi Fehler from Vitawell



Leider muss ich dieses post schreiben weil der Whirlpool (Jacuzzi) ich vom www.vitawell.de, eine firme im Berlin, ist wirklich problematisch geworden. Der firme meldet sich auch nicht mehr. Ich wird gern das hier nicht schrieben. Ich hoffe das verändert sich noch oder zu mindest andere Käufer sind vom die Problem informiert. Der firme ist vom Robert Lamprecht betrieben und oft (immer für mich) sein Sonn Bernard Lamprecht macht der Montage arbeit.

Eigentlich habe ich schon eine review im google geschrieben aber der Datei bilde funktionieren da nicht. hier noch mal die punkten und bilde:

Ich habe eine Außenwhirlpool (1500L) von die verkauft für deutlich über dein Baumarkt Pool Preis, so ein Preis lohnt sich nicht, meine Meinung nach. Die firme reden auch keine klar text, das ich die nicht mehr vertrauen kann. Ich habe auch der gleiche Problem das man die nicht am Telefon ran kriegst. Die haben jetzt auch meine Termin zwei mal verschoben und nicht zurück gerufen. Der Pool funktioniert an sich aber es kommt immer Probleme mit der Heizung. Immer wieder springt der Sicherung aus.


der Sicherung has noch mal raus gesprungen diese Woche (16/07/2018) - Datei folgt

Ich musste selbe eine Datanlogger dazu kaufen um zu sehen das es funktioniert nicht, es gibt keine eingebaute Meldung das es funktioniert nicht. Das Heist der Pool konnte im winter einfrieren oder wenn ich das nutzen will, hat es keine warme Temperatur. Die Heizung war ein mal komplett Tot (das haben die zeitlich ausgetauscht aber nur mit 2kw leistung statt 4kw). Nach viel zeit und kämpfen habe ich wieder der richtiger 4kw Leistung. Aber der Ursache ist immer noch nicht bekannt und die versuchen es nicht zu lösen. der Pool ist nicht wirklich praktisch aufgebaut weil um der Heizung Sicherung wieder einzuschalten oder der Wasser abzulassen muss mann der ganze Seite abschrauben. Eine Revision klappe war im Verkaufs Gespräch versprochen aber niemals eingebaut. Die haben gesagt die werden es nachträglich einbauen. Aber das haben die nicht gemacht. Die Dämmung platten fallen auch ab und sind nicht fest, kein bodenplatte Dämmung und da sind viele luftlöcher zwischen platte und Gehäuse. Einfach Schlecht gedämmt und das kostet mir Geld immer wieder.

Wednesday, November 2, 2016

Automatic watering system using Gardena 1197 + OpenHab + Pilight

I was tired of having the repetitiveness of watering my garden every day so I wanted a solution to manage the garden watering. It was not as simple as just using one circuit because my garden is spread out, so different areas need different times and water pressure is a problem. I also did not want to dig my garden up to lay down new water pipes, so I wanted to be able to use my existing garden hose's.

The solution cost was to use Gardena automatic water distributor along with an single electronic valve from Hunter. This keeps the electrics simple and the connections plug and play. The control was done with openhab running on a raspberry pi, which triggered the valve via a remote 433mhz switch. You could obviously use a valve per circuit, but this requires another bridge to the PI and I had the 433Mhz already set up with pilight. As it is below you can also switch the valve with an electric pump, which I sometimes do when I have collected enough rain water.

Parts list:
1.) Remote switch - 25 Euro - Although I had this already
2.) Gardena automatic water distributer - 55 Euro
3.) 24 V AC Transformer - 12 Euro
4.) Hunter PGV-100 valve - 16 Euro - basically cheaper than Gardena version
5.) Raspberry PI - 40 Euro - although had this already as well
6.) Aurel 433Mhz transmitter
7.) Various garden houses to different sections of the garden, 4 circuits in use, but up to 6 can be used


View of the switch, the transformer and hunter valve

Garden Distributor
The Gardena distributor works quite simply by switching to the next circuit when there is no water pressure for a certain period of time (I was using about 10 seconds). So with a on-off-on-etc pattern you can control up to 6 circuits with different time periods if you want.

View of control panel in Openhab basic UI
Pilight needs to be installed and the pilight binding needs to be setup inside openhab

addons.cfg:
    pilight:kaku.host=192.168.2.168
    pilight:kaku.port=5000
    pilight:kaku.delay=1000

Pilight devices:
     "devices": {
                "desklamp": {
                        "protocol": [ "kaku_switch" ],
                        "id": [{
                                "id": 15831690,
                                "unit": 1
                        }],
                        "state": "off"              
        },

Items file:
Switch  KakuDeskLamp    "Water"               {pilight="kaku#desklamp"}
Switch  WaterTest    "Water Test"
Switch  StartProgram    "Start Program"
Switch  KakuSmallBathFan    "Small bath fan"               {pilight="kaku#smallbathfan"}
Number      Irrigation_LawnMins     "Lawn Sprinkler [%d mins]"  <water>         (Irrigation)
Number      Irrigation_Pause     "Break [%d mins]"  <water>         (Irrigation)
Number      Irrigation_Multiplier     "Multiplier [%d mins]"  <water>         (Irrigation)
Number      Irrigation_Circuits     "Circuits [%d]"  <water>         (Irrigation)
Number      Irrigation_ActiveCircuit     "Circuits [%d]"  <water>         (Irrigation)

Number      Irrigation_Repeats     "Repeats [%d]"  <water>         (Irrigation)

Openhab rules:
    rule "Enabling irrigation"
    when
    Item StartProgram changed from OFF to ON or
    Time cron "0 45 7 1/1 * ? *"
    then
      var i = 0
      var Number lawnMins = Irrigation_LawnMins.state as DecimalType
      var Number pause = Irrigation_Pause.state as DecimalType
      var Number Multiplier = Irrigation_Multiplier.state as DecimalType
      var Number Circuits = Irrigation_Circuits.state as DecimalType
      var Number Repeats = Irrigation_Repeats.state as DecimalType
      lawnMins = lawnMins*1000
      if (Multiplier != 0)
      {
        lawnMins = lawnMins*Multiplier
      }
      logInfo("Irrigation", "Circuits " + Circuits + " multiplier " + Multiplier)
      while ((i=i+1) < Circuits+1) {
        var j = 0
        while ((j=j+1) < Repeats+1) {
                logInfo("Irrigation", "Repeat " + j)
                sendCommand(KakuDeskLamp, ON)
                Thread::sleep(100)
        }
    
        logInfo("Irrigation", i + " lawnMins " + lawnMins)
        sendCommand(Irrigation_ActiveCircuit, i)
        Thread::sleep(lawnMins.intValue) //*lawnMins)
        j = 0
        while ((j=j+1) < Repeats+20) {
                logInfo("Irrigation", "Repeat " + j)
                sendCommand(KakuDeskLamp, OFF)
                Thread::sleep(100)
        }
   
        sendCommand(Irrigation_ActiveCircuit, 0)
    
        Thread::sleep(1000*pause.intValue)
      }
      sendCommand(StartProgram, OFF)
    end


Thursday, December 17, 2015

Qt issue /problem with frameless window flickering on ubuntu

When using a frameless window in QML (prehaps directly from c++ as well) you need to manually allow dragging of the window. The first solution I found was like this:

Window  {
    id: appWindow
    flags: Qt.Window|Qt.FramelessWindowHint

    MouseArea {
        id: mouseRegion
        anchors.fill: parent;
        property variant clickPos: "1,1"

        onPressed: {
            clickPos  = Qt.point(mouse.x,mouse.y)
        }

        onPositionChanged: {
            var delta = Qt.point(mouse.x-clickPos.x, mouse.y-clickPos.y)
            appWindow.x += delta.x;
            appWindow.y += delta.y;
        }
    }
}

This worked on windows, but on Ubuntu the window flickered on Ubuntu due to a race condition:
Mouse move event A:
                Receive mouse position relative to app position Y
                Update app to position X

Mouse move event B:
                Receive mouse position relative to old app position Y (and not X as expected)
                Update app to position Z

The second effectively incorrectly does “double” the delta…


The fix is then to use a global cursor position as reference, so the new solution is then

Window  {
    id: appWindow
    flags: Qt.Window|Qt.FramelessWindowHint
    MouseArea {
        id: mouseRegion
        anchors.fill: parent;
        property variant clickPos: "1,1"
        property variant appStartPos: "1,1"

        onPressed: {
            // fetch global position due to bug on ubuntu
            clickPos = gApplicationController.getCursorPos()
            appStartPos = Qt.point(appWindow.x, appWindow.y)
        }

        onPositionChanged: {
            var newPos = gApplicationController.getCursorPos()
            var delta = Qt.point(newPos.x-clickPos.x, newPos.y-clickPos.y)
            appWindow.x = appStartPos.x+delta.x;
            appWindow.y = appStartPos.y+delta.y;
        }
    }
}

Note you need to set up a c++ class that gets the cursor position something like

class AppController : public QObject
{
    Q_OBJECT

    QQmlApplicationEngine m_engine;
public:
    Q_INVOKABLE QVariant getCursorPos();
}

AppController::AppController()
{
    m_engine.rootContext()->setContextProperty("gApplicationController", this);
}

QVariant AppController::getCursorPos()
{
    return QVariant(QCursor::pos());
}

Friday, November 27, 2015

Running ubuntu/linux on a xen server 6.5 with a passthrough GPU

For a while I was struggling to get ubuntu to work with my NVIDIA GPU in passthrough mode on xenserver. Xorg start, but then just fail... and those xorg messages are sooo helpful ;). Any way it turns out xorg could not correctly map the right driver to the correct PCI device. I had to add the PCI bus ID to the xorg.conf like here:

 BusID "PCI:0:12:0"

 Found this info here: https://wiki.archlinux.org/index.php/Xorg#More_than_one_graphics_card:

 my devices "lspci | grep -e VGA -e 3D":

00:02.0 VGA compatible controller: Cirrus Logic GD 5446
00:06.0 VGA compatible controller: NVIDIA Corporation GK104GL [Quadro K5000] (rev a1)

Sunday, February 1, 2015

Temperature and Relative Humidity

Below is a plot of my measured temperatures and humitidy for my house over time. Data is collected from Oregon sensors over 433hz wireless transmission to the raspberry pi (with 433hz receiver) and stored in Google docs. The graph below is created with the help of highcharts using java script.

12/12/2014

give me input

Sunday, January 25, 2015

Curl C to google sheets

A quick post about using the CURL C API to upload data to google spreadsheets. I used it upload temperature and humidity data that I am tracking at home. There are a few steps

1.) create a google spreadsheet the normal way (with headings for each data item you want to save)

2.) get auth from google:
                curl_easy_setopt(curl, CURLOPT_URL, "https://www.google.com/accounts/ClientLogin");
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "Email=YOUREMAIL&Passwd=YOURPASSWORD&accountType=GOOGLE&source=cURL&service=writely");

3.) Form your data in the correct XML format:
      sprintf(postData, "<entry xmlns='http://www.w3.org/2005/Atom' xmlns:gsx='http://schemas.google.com/spreadsheets/2006/extended'> <gsx:date>%s</gsx:date>  <gsx:time>%s</gsx:time>  <gsx:temp>%f</gsx:temp>  <gsx:relhum>%f</gsx:relhum><gsx:location>%d</gsx:location><gsx:device>oregon</gsx:device></entry>", 
dateStr, timeStr, s->getTemperature(), s->getHumidity(), s->getChannel());

4.) Post the data with the correct fields to the spreadsheet:
                        curl_easy_setopt(curl, CURLOPT_URL, "https://spreadsheets.google.com/feeds/list/YOURSPREADSHEETKEY/1/private/full");
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, strlen(postData));
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postData);
curl_easy_setopt(curl, CURLOPT_POST, true);

struct curl_slist *headerlist=NULL;
char authHeader[600];
sprintf(authHeader, "Authorization: GoogleLogin auth=%s", g_auth);
cout << "auth header " << authHeader << endl << flush;
headerlist = curl_slist_append(headerlist, authHeader);
headerlist = curl_slist_append(headerlist, "GData-Version: 3.0");
headerlist = curl_slist_append(headerlist, "Content-Type: application/atom+xml");


Full function code at https://github.com/arcanon/curlgooglespreadsheet/blob/master/googledocs-c.cpp

Monday, February 24, 2014

Modifying coova chilli to allow anonymous users for a private hotspot using automatic MAC addresses

So I spent a lot of time looking for a way to allow anonymous users to a coova chilli hotspot. Anonymous in the sense that a user can just click a button and get 30 min Internet access without having to type a password and what not. It made complete sense to use the MAC address as the users ID, but this only worked if you entered the MAC already. And NO where did I find that you could accept any new MAC address as a new user. Eventually I learnt enough about coova chilli to do this myself. The trick is to change the function dologin in the haserl script /etc/chilli/www/config-local.sh (use your password instead of XXXX) to


dologin() {
    res="$(echo "select username from radcheck where username ='$REMOTE_MAC';" | mysql -u root -pXXXX radius)"
    if [ "$res" = "" ]
    then
        echo "insert into radcheck (username, attribute, op, value) values ('$REMOTE_MAC', 'Cleartext-Password', ':=', 'password');" | mysql -u root -pXXXX radius
        echo "insert into radusergroup (username, groupname) values ('$REMOTE_MAC', '30min');" | mysql -u root -pXXXX radius
    fi
#    url=$(chi_login_url "$FORM_username" "$FORM_password" "$FORM_userurl")
    url=$(chi_login_url "$REMOTE_MAC" "password" "$FORM_userurl")
    cat <<ENDHTML
<html><head>
<meta http-equiv="refresh" content="0;url=$url"/>
</head></html>
ENDHTML
    wisprLoginResultsURL "$url" 
}


Once you have done this, every time a new device logs into your web page, the script will check if the MAC address exists or not. If not it will require any username. I changed my login page to just be a button and made the other fields hidden, like so edit /etc/chilli/www/login_form.tmpl :

<!--
  --  The login form
  -->

<div id="login-form">
<table>
<tr>
<!--  <td>Usernamebb</td> -->
  <td><INPUT NAME="username" VALUE="user1" TYPE="hidden"></td>
</tr>
<tr>
<!--  <td>Password</td> -->
  <td><INPUT NAME="password" VALUE="password" TYPE="hidden" TYPE="password"></td>
</tr>
<tr>
  <td colspan="2" nowrap align="center">
    <input type="submit" name="button" value="Login & Accept Terms">
  </td>
</tr>
</table>
</div>



Wednesday, February 12, 2014

Hacking a hermes pro router to get a isdn line working

So I had an issue that a Hermes Pro/S+ router died. This is used by pharmacy software (more specifically Apotheken Software) to get order supplies from the supplier. Now of course when we asked the support company for some help, they immediately said that would be 1000 euros please. In fact they did not want to tell us the price. They just wanted to charge directly. And they did not offer any other options.

So instead i ordered a Hermes Pro/SH online from ebay. So it arrived. Cool! Then i found out that it did not have an IP written down. For anyone that may know, that means its not really easily configurable. The next way to do this was over the V24 port. This is a serial port and should connect easily to your PCs COM port. That's if u still have one:). Basically a Ethernet to 9 pin serial port cable is necessary. Now looking online, they did exist, but that meant ordering a cable and we did not really have the time for that. So a i decided to make my own. Just cut open a Ethernet cable and join it to 9 pin serial cable (USB adapter which i bought for my laptop).

So i did this following the standard that exists for Ethernet to 9 pin serial. Then i fired up putty to telnet into the router, but nothing:( my heart sank. So much time and still no solution. And the business needs this to run properly...  so i head home a bit unhappy. On the way i remember one point of data i got from the sales guy. That was that the Hermes router was built from an old Cisco router. So i start googling a Cisco V24 port router. I find a page detailing the mapping for Cisco. And what do u know, its not the same as the standard that i tried before! So i do some rewiring and fire up putty again. I have never been so happy to see a login screen! This was the result:

Wednesday, January 1, 2014

Better Stereo (?) using Rectified Left and Right images and stereo Q matrix with and without zero disparity

Left and right images with zero disparity calibration and the resulting disparity map. With higher possible disparity values (this is a paremeter for the alogithm), the left of the map is black, but gives better results in general for the found disparity.
So the stereo camera is important to provide 3D information of the world that is currently visible. The difference in position of an object in the left and right images defines the objects position. With this information we can start reconstructing the world around the camera. So there are two points:
  1.) Determining the relative position of objects in the left and images in terms of how many pixels the object's position is different from left to right. This is done using something like stereo block matching.
  2.) Translate this pixel difference in to real world values like centimeters and meters using the camera parameters.

Before 1 and 2 can be done, the left and right images need to be rectified to fit into the normalized camera reference point, so the algorithms can correctly run. See references on epipolar lines or rectified stereo images.

The one issue I ran into was how was the Q matrix in 2 above defined. ScaViSLAM uses a Q matrix with "zero disparity" this means that the Q matrix looks like this (see StereoCamera::Q()):
  1    0    0    Cx
  0    1    0    Cy
  0    0    0     f
  0    0    1/b  0

where (Cx, Cy) is the camera center point, f is the camera focal distance and b is the baseline distance (distance between the left and right camera center points). To obtain this value using openCV function cvStereoRectify, you must use the CV_CALIB_ZERO_DISPARITY flag. If you don't use this then your matrix looks like:

  1    0    0    Cx
  0    1    0    Cy
  0    0    0     f
  0    0    1/b  b'/b

Where b' is the shift between the 2 cameras. Using a non zero disparity should help to conserve pixel area after rectification. But essentially both should work, its just a question of what the different algorithms are expecting. ScaViSLAM uses a hierarchy of images, so recalculates the camera parameters for each scale, which it then needs the zero disparity matrix. You can do the same calculations for non-zero disparity, but it was easiest to get started using the CV_CALIB_ZERO_DISPARITY flag.

Left and right images with non-zero disparity calibration and the resulting disparity map. More area of the captured images is preserved. The disparity map looks quite difference due to the different Q matrix that will reproject the points

I cam across this blog: http://robotpingpong.blogspot.de/2013/03/small-progress-in-triangulation.html. Here the results for the rectification are much more warped. I guess because his 2 PS3 cameras are not so closely arranged. The raspberry pi camera gives good results here because you can mount then closely (6.5cm apart). His cameras I think were 50cm apart.

Working with raspivid for low latency and other issues with compression

So after I got ScaViSLAM working, I had an issue with getting my raspi stereo camera working at 640x480 as expected (I wanted to use 640x480 because the perf at 1920x1080 was too slow, but the perf would probably get better in a release build). The issue was that I was getting bursts of 17 frames in the stream. Instead of the h264 stream from the pi delivering one frame as often as possible, it was sending 17 frames in one packet. This meant that there was a latency of 33ms*17=500ms. This is not so usable. I eventually analyzed the H264 stream by detecting the NAL markers, which showed that the H264 decoder was decoding 17 frames for a I frame packet (buffer starting with 0x00000125). An I frame is a single frame that is only compressed against itself, there is no dependency to previous frames. A good reference for the H264 basics is
http://keyj.emphy.de/files/projects/SA_paper.pdf. I don't know if another decoder could handle this better or if this is normal, but then the solution was to increase the frequency of the I frames. using "raspivid -g 1" the I frames are then sent every frame. Then the problem is solved because then I receive as new a frame as fast possible and my video queue is always at most 1 deep (unless whatever algorithm that is running on the server is too slow to consume the stream).

I added code in
https://github.com/arcanon/raspbot/blob/master/h264decoder.h
to detect the NAL markers and also check how full the frame queue was.


 if ((data[i] == 0) &&
  (data[i+1] == 0) &&
  (data[i+2] == 0) &&
(data[i+3] == 1))
{
      NALCount++;
      nalFound = true;
....
}
and
if ((m_reader->framesInQueue()- start) > 1)
{
   falseCount+= (m_reader->framesInQueue()- start);
   printf("%s, error frames more %d size %d fa %d, nc %d fc %d\n", this->m_vid_server.c_str(), (m_reader->framesInQueue()- start), prevSize, framesAdded, NALCount, falseCount);    }

Saturday, December 7, 2013

A step towards SLAM - compiling ScaViSLAM for windows

So after much fighting and nail biting I have managed to get ScaViSLAM to compile on windows (why not just use linux? I don't really have a linux system right now and generally have fewer issues with windows). I had to fix a lot of cmake files and figure out how libraries should be compiled with the correct runtime libraries (need to match for all dependencies). I have tested it with the new college data. The main code base is at:
   https://github.com/strasdat/ScaViSLAM
and my fork is at
    https://github.com/arcanon/ScaViSLAM

I have also made a fork of the vision tools at https://github.com/arcanon/VisionTools to update some things to support windows. I guess other packages also need some special changes and those are not all there yet.

Runs at 2-3 fps with a debug build (all dependent libraries as well). Very, very fast :). on the default width = 512 and height = 384.

Proof that ScaViSLAM runs on windows

So the next step is to plug the previous stuff I did with the stereo camera into this system from http://subgroup-ash.blogspot.de/2013/11/stereo-camera-with-block-matching.html. The UI of ScaViSLAM is also really nice, all GL and has perf and nice input fields. So the final system I create would change to this system probably.

To plug in my stereo camera, I have to work out the relation from the stereo matrices calculated in the stereo calibration because ScaViSLAM uses a slightly different start point. I think there the stereo camera is always calibrated and the camera "baseline" is well defined. Should work, but need to figure out the maths that gets the right values at the right places.

In general the next steps could be:
   1.) Compiling a complete ROS (robot operating system). This could be linux or windows, mostly just important to have access to the rich environment that ROS offers. such as the PTAM implementation.
   2.) Think about porting ScaViSLAM to that environment.
   3.) Think about using PTAM (http://wiki.ros.org/ethzasl_ptam/ptam)

Tuesday, November 19, 2013

Stereo camera with block matching

So I managed to start using my stereo camera to seeing some depth and got the first steps working to generating a point cloud of the scene.
Top row: Left and right images (rectified). and disparity image is lower left using the block matching algorithm.
The new camera uses adjustable screws, see image below:
New camera setting with adjustable screws
I used the code/app from http://blog.martinperis.com/2011/01/opencv-stereo-camera-calibration.html to calibrate the cameras and work out there matrices/ rectifying values for each feed. Once the feeds are rectified (another way to describe this would be to normalize the images, so that they can be interpreted correctly) then the block matching algorithm can be used to determine the disparity map. Next would be to calculate the actual distance of each point from the camera and then we can generate a point cloud. The algorithm only runs at about 5 fps right now on the HD frame on my NVS 4200. I checked with NVIDIA nsight profiling and the block matching kernel takes 188ms, which is the reason for the poor perf. See image below

Profile using NVIDIA nsight of stereo block matching
 As always, the code is up at https://github.com/arcanon/raspbot. I know, it won't really compile, which I hope to fix. Next I want to generate the point cloud and then I will make everything easily compile-able. well as easy as you can get, because its using a whole bunch of complicated libraries...

Sunday, November 10, 2013

Raspberry Pi Stereo Camera

Stereo camera with 2 raspberry pi's
So I made my first stereo camera this weekend with 2 raspberry pi's. It actually worked out pretty easily. The exact stereo angle of the camera's is not exact and only controlled with pieces of paper and elastic bands. The blue bands in the middle and paper on the outer edge tilt the camera a little more inwards. Here is a example anaglyph stereo (you will need red/blue stereo glasses to view it properly):

It would be best to have exact screws which you can use to adjust the angles and such. There are small holes on the camera that would allow these screws to be attached, so its just a matter of finding the right adjustable screws. Although thinking of that now, it should not be a big thing. I know the stereo alignment is a bit funny, which should be fixed, but my eyes where able to find the right focus and you can see the 3D effect quite nicely. The code is up at https://github.com/arcanon/raspbot. It won't compile out of the box, but have a look at video reader for the capture loop/anaglyph composition.

The CUDA kernel that composites the kernel looks like this:

__global__   void anaglyph_dev(char* imageLeft, char* imageRight, char *imageOut, int pitchInputs, int pitchOutput, int width, int height)
{
    int x = blockIdx.x * blockDim.x + threadIdx.x;
    int y = blockIdx.y * blockDim.y + threadIdx.y; 

    if (x >= width || y >= height)
        return;

    int linearPosInputs = y*pitchInputs + x;
    int linearPosOutput = y*pitchOutput + x*4;

    // Red
    imageOut[linearPosOutput]   = imageLeft[linearPosInputs];
    imageOut[linearPosOutput+1] = 0;
    imageOut[linearPosOutput+2] = imageRight[linearPosInputs];
}

Sunday, October 27, 2013

OpenCV GPU ORB issues

So I was noticing some issues with ORB on the GPU. The descriptors obtained at (in https://github.com/arcanon/raspbot/blob/master/video_reader.cpp):

                orbGpu(finalFrame, maskFrame, gpuKeyPoints, gpuDescriptors);
                orbGpu.downloadKeyPoints(gpuKeyPoints, keyPoints);

These were somewhat "unreliable" because there was no Gaussian blur before calculating the descriptor values. You could see this easily if you paused the video, so that the key points were always calculated on the same image. In this case, for the GPU the points jumped around while for the CPU they remain constant. This was fixed with
              orbGpu.blurForDescriptor = true;

This issue is well described at http://answers.opencv.org/question/10835/orb_gpu-not-as-good-as-orbcpu/.

The next step will be a stereo camera setup, so that I can filter out the background, which will help a lot filtering out false positives.

The other issue is that the camera has an exposure that is too long, this is a problem for the speed at which the detection happens. You can't move the robot to fast (or the objects can't move past the robot) because then they start to blur and then nothing is recognizable.

Sunday, October 6, 2013

Raspbot helps find my cofee

Ever lost your coffee and needed some help finding it? I have and it can be a stressful situation, as you don't have the coffee to help calm your nerves. That is where the raspbot jumps in to save the day. Just make sure you have a distinct enough mug, so that it does not get lost in the background. This makes use of OpenCV and object detection. It streams the video from a raspberry pi to a server, which is running OpenCV and has a GPU. Then GPU is then used to decode the H264 stream. Then either the GPU or the CPU is used to analyze a frame for interesting information (in this case, where is the mug). OpenCV has GPU and CPU support, so you can choose.
System overview

Here is the code for the server https://github.com/arcanon/raspbot/blob/master/video_reader.cpp. The other core code is also in that repository. You obviously need to OpenCV. I was running on windows, you have to fight a bit to get it compiled on windows, I will give some tips at some point on that, maybe its also easier with newer versions.

Capture Thread:
1.) Winsock buffer connects to netcat client on PI
2.) Buffers data and passes to H264StreamSource
3.) Data then Passed to GPU for decoding

Detection Thread: 
1.) Frame from capture thread recieved
2.) Converts to grey scale
3.) uses ORB/SURF for feature extraction. On CPU or GPU.
4.) Compares against detection object.
5.) Sets up commands to send to PI

Command Thread: 
1.) Connects to Python client on PI
2.) When Detection thread has commands, these are sent to the PI.
Server Threads

Raspberry PI threads/processes

Sunday, September 22, 2013

Fix SPI commands being ignored when multiple are sent

My last code had a bug. When two commands were sent from the python script https://github.com/arcanon/raspbot/blob/master/ardspi.py. Like so:

  sendByte(ard, leftStop)
 sendByte(ard, rightStop)
The first command would cancel the second because the code on the atmega resets the sent command https://github.com/arcanon/raspbot/blob/master/Blink.ino with readBytes[0] = 0. The SPI receive processing is asynchronous (well, I guess the SPI interrupt function is serial with respect to clocks), but you don't know when the function is run. So the first command is received and while the command processing in the main loop is running, the next command was read into readBytes[0] which is then overwritten.
The fix is to have a ring buffer which saves all the commands and allows the main loop to run asynchronously to the SPI interrupt function. The new blink.ino contains the fixed code.

Monday, September 9, 2013

A New Build, speed control and atmega/Aduino read-back to raspberry PI

So I finally got some time to provide the updated info for my rasp bot. In this post, I give updates on how I have rebuilt the bot to have drive more accurately (the last version with such small wheels did not fair so well on different surfaces and the motors were not great) and I talk about the SPI enhancements for speed control and voltage read back.

The new build:

1.) a left and right servo for the wheels
2.) much larger wheels
3.) a wooden chassis to hold bread board and camera

I learnt during the upgrade, that wood and elastic bands are really good materials to use during building custom projects. Wood because it's relatively easy to form and elastic because you can hold the different pieces together easily without having to glue everything permanently. Later you can then reconfigure things with ease. 

In this version, I switched back to a mini bread board, so that I can add things to the circuit more easily. The last version was all soldered together, which was great fun, but really not practical in the long run when you are still trying things out. For the motors, I bought some servos, which are normally intended for controlled angler movement, but I removed these circuits and restrictions. Then I use them as plain DC motors with gear. I liked this solution because the servos were relatively cheap and provide good power. The big wheels I found a model shop around the corner. They are pretty much directly attached to the servos (the servos came with small plastic discs that I could glue to the wheels with a CD providing a in surface between the wheel and the servo disc attachment). This is also really nice because was quite difficult to find a simple gear system for connecting a DC motor to wheels. Mostly others buy a remote toy and modify that because then all the parts are pretty much there. However, you are not able the to build your own design.

Lastly, I now have the new raspberry pi camera. It's great for use with raspivid and streaming. You can get great video and choose your compression(a problem when you only have 440KB/s dsl uploads). That's all stuck or bound together as shown in the picture.

Speed control and voltage read back:

I was having some issues with capturing the video and analysis thereof when moving. The issue Is that with movement it takes a while for the stream to settle. Otherwise there is just to much noise or blurred images(especially in low light) to make reliable descisions). one solution is to make the movement less jerky, as up until now I was just turning the motor on and off (with an input voltage of 4.8v). I did reduce the input to just 3.6, which helped, but still was not good enough. So I changed the code to send a speed value to the atmega with every movement control. The atmega then uses this value to toggle the time which the enable pin of the hbridge(L293), so that it is only on a certain percentage of the time. This is basically software PWM (pulse wave modulation). The atmega does this by counting loop cycles and switching the enable pin on for the number of loop cycles sent from the python script running on the PI. I could also use the atmegas PWM pins, but those conflict with the SPI pins (the MSO and SS pins are 2 of the 3 PWM pins).

I have updated the source https://github.com/arcanon/raspbot/blob/master/Blink.ino and the python script, https://github.com/arcanon/raspbot/blob/master/ardspi.py. The SPI read back is done by using the quick2wire duplex method. Note that 1 byte from the slave is read back at the exact same time as 1 byte from the master. This means the slave needs to pre-prepare the data to be sent or you discard the first byte. I have just done the later for now. I send back the 10 bit conversion of the voltage measured by the adruino on a pin which is connect to the positive battery supply of the motors (3.6V) via a 10K resistor. The same connection is connected via another 10K resistor to ground. The voltage is then measured at 1.8V, divided as expected. I have not done time measure measurements to see how this varies over time.

The python script also contains some networking code, which I will write about in another post. That code allows the PI to take to a server which is capturing the video stream (from raspivid) and then doing various video analysis. I can then make use of a dekstop GPU to improve the speed of the analysis for object detection and such.

Tuesday, March 26, 2013

Reading back data over serial from the atmega

Just to add to my last post, I used the "minicom ama0", method of monitoring data from the atmega. Some more details here. I can't remember if I needed to change some special settings, but if anyone has issues I can check my settings if need be.

https://projects.drogon.net/raspberry-pi/gertboard/using-the-arduino-ide/

Sunday, February 24, 2013

Rasberry Pi Robot with L293, atmega8 using SPI communication

This project was to build a robot from the ground up using the raspberry pi because it has good support for wireless and eventually a built in camera (here I use a web cam).  Eventually the robot can be controlled remotely via key strokes or can also listen to some basic voice commands (via google voice recognition found in raspberrypi.org forums). A video demo is still to come because I want to improve how the voice works. Currently, switching the motors on makes too much background noise for it to detect the next information.

I went with connecting the Raspberry pi to the atmega via SPI because eventually it might be nice to use the atmega for analog input as well. Bi directional communciation should not be a problem. The atmega runs at 3.3V, so that should not cause issues. In addition, the atmega provides a buffer to the motor driver L293, so if some power backlash happens the PI is somewhat protected. Note I am a software guy, so forgive me if I do something electrically bad. 
The raspbot - crown is just some decoration and  yes raspberry pi is misspelt. 
The code for the atmega is located at https://github.com/arcanon/raspbot/blob/master/Blink.ino and the python script that talks to the atmega via Quick2Wire is at https://github.com/arcanon/raspbot/blob/master/ardspi.py. 

I used the raspberry pi as the programmer for the atmega using - https://projects.drogon.net/raspberry-pi/gertboard/. Note that that you have to make sure you use the right fuse settings I did something like this

avrdude -vvvv -c gpio -p atmega8 -U lock:w:0x3F:m -U lfuse:w:0xe4:m -U hfuse:w:0xda:m -i4000

At one point I "killed" the chip by using the wrong fuses (I set it to an external clock when I had none), but managed to fix it. See details -http://www.raspberrypi.org/phpBB3/viewtopic.php?p=235388#p235388.

Issue with bit banging via avrdude/SPI and using the SPI device. I could not do this at the same time, so every time I reprogrammed the atmega, I had to restart the PI so that I could use my python script again. Lame, but true :/.

To view the webcam I used: 
 ./mjpg_streamer -i "./input_uvc.so  -f 15 -r 640x480" -o "./output_http.so -w ./www"

Circuit diagrams and breadboard from Frizing 

Breadboard layout
Circuit diagram
Links:
Basic SPI tutorial from: http://mitchtech.net/raspberry-pi-arduino-spi/



Monday, December 24, 2007

Sometimes, we would like to live in sub-worlds that allow us to relax and escape the large conflicts of life. Like making money, getting a degree and christmas presents. The sub-world helps to correct the imbalance found in our world. I have yet to find a way in which we can correct imbalances found in a given world while still in that world.

This is a sub-world I found in Beverlac.
Posted by Picasa