Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - GoldenEagle

Pages: 1
1
You put the code in the same place you've got it already, just expanded. Here, kind of like this:
Code: [Select]
   if (!lastWiiState.IRState.Found1)//mouse down
                {
                    //lastWiiState.IRState.Found1 = ws.IRState.Found1;
                    smoothingBufferIndex = 0;//resets the count
                                     
                    Win32.INPUT[] buffer = new Win32.INPUT[5];
                    buffer[0].type = Win32.INPUT_MOUSE;
                    buffer[0].mi.dx = (int) (warpedX * 65535.0f / screenWidth);
                    buffer[0].mi.dy = (int) (warpedY * 65535.0f / screenHeight);
                    buffer[0].mi.mouseData = 0;
                    buffer[0].mi.dwFlags = Win32.MOUSEEVENTF_ABSOLUTE | Win32.MOUSEEVENTF_MOVE;
                    buffer[0].mi.time = 0;
                    buffer[0].mi.dwExtraInfo = (IntPtr) 0;

                    buffer[1].type = Win32.INPUT_MOUSE;
                    buffer[1].mi.dx = 0;
                    buffer[1].mi.dy = 0;
                    buffer[1].mi.mouseData = 0;
                    buffer[1].mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
                    buffer[1].mi.time = 1;
                    buffer[1].mi.dwExtraInfo = (IntPtr) 0;

                    buffer[2].type = Win32.INPUT_MOUSE;
                    buffer[2].mi.dx = 0;
                    buffer[2].mi.dy = 0;
                    buffer[2].mi.mouseData = 0;
                    buffer[2].mi.dwFlags = MOUSEEVENTF_LEFTUP;
                    buffer[2].mi.time = 1;
                    buffer[2].mi.dwExtraInfo = (IntPtr) 0;

                    buffer[3].type = Win32.INPUT_MOUSE;
                    buffer[3].mi.dx = 0;
                    buffer[3].mi.dy = 0;
                    buffer[3].mi.mouseData = 0;
                    buffer[3].mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
                    buffer[3].mi.time = 1;
                    buffer[3].mi.dwExtraInfo = (IntPtr) 0;

                    buffer[4].type = Win32.INPUT_MOUSE;
                    buffer[4].mi.dx = 0;
                    buffer[4].mi.dy = 0;
                    buffer[4].mi.mouseData = 0;
                    buffer[4].mi.dwFlags = MOUSEEVENTF_LEFTUP;
                    buffer[4].mi.time = 1;
                    buffer[4].mi.dwExtraInfo = (IntPtr) 0;

                    Win32.SendInput (5, buffer, Marshal.SizeOf (buffer[0]));

                                               

                    switch (calibrationState)
                    {
                        case 1:
                            srcX[calibrationState - 1] = x;
                            srcY[calibrationState - 1] = y;
                            calibrationState = 2;
                            doCalibration ();
                            break;
                        case 2:
                            srcX[calibrationState - 1] = x;
                            srcY[calibrationState - 1] = y;
                            calibrationState = 3;
                            doCalibration ();
                            break;
                        case 3:
                            srcX[calibrationState - 1] = x;
                            srcY[calibrationState - 1] = y;
                            calibrationState = 4;
                            doCalibration ();
                            break;
                        case 4:
                            srcX[calibrationState - 1] = x;
                            srcY[calibrationState - 1] = y;
                            calibrationState = 5;
                            doCalibration ();
                            break;
                        default:
                            break;
                    }
                    // }//calibtation state
                }//mouse down               
                else
                {
                    Win32.INPUT[] buffer = new Win32.INPUT[1];
                    buffer[0].type = Win32.INPUT_MOUSE;
                    if (enableSmoothing)
                    {
                        System.Drawing.PointF s = getSmoothedCursor (smoothingAmount);
                        buffer[0].mi.dx = (int) (s.X * 65535.0f / screenWidth);
                        buffer[0].mi.dy = (int) (s.Y * 65535.0f / screenHeight);
                    }
                    else
                    {
                        buffer[0].mi.dx = (int) (warpedX * 65535.0f / screenWidth);
                        buffer[0].mi.dy = (int) (warpedY * 65535.0f / screenHeight);
                    }
                    buffer[0].mi.mouseData = 0;
                    buffer[0].mi.dwFlags = Win32.MOUSEEVENTF_ABSOLUTE | Win32.MOUSEEVENTF_MOVE;
                    buffer[0].mi.time = 0;
                    buffer[0].mi.dwExtraInfo = (IntPtr) 0;

                    Win32.SendInput (1, buffer, Marshal.SizeOf (buffer[0]));
                }
            }//ir visible
            else
            {
                if (lastWiiState.IRState.Found1)//mouse up
                {
                    //lastWiiState.IRState.Found1 = ws.IRState.Found1;
                    //Console.WriteLine ("aw");
                    Win32.INPUT[] buffer = new Win32.INPUT[2];
                    buffer[0].type = Win32.INPUT_MOUSE;
                    buffer[0].mi.dx = 0;
                    buffer[0].mi.dy = 0;
                    buffer[0].mi.mouseData = 0;
                   
                    buffer[0].mi.dwFlags = MOUSEEVENTF_LEFTUP;
                    buffer[0].mi.time = 0;
                    buffer[0].mi.dwExtraInfo = (IntPtr) 0;

                    buffer[1].type = Win32.INPUT_MOUSE;
                    buffer[1].mi.dx = 0;
                    buffer[1].mi.dy = 0;
                    buffer[1].mi.mouseData = 0;
                    buffer[1].mi.dwFlags = Win32.MOUSEEVENTF_MOVE;
                    buffer[1].mi.time = 0;
                    buffer[1].mi.dwExtraInfo = (IntPtr) 0;                 

                    Win32.SendInput (2, buffer, Marshal.SizeOf (buffer[0]));                   
                    ;
                }//ir lost           
            }

The number of inputs changed to 5 because we added 3 additional buffer blocks (2, 3 and 4, corresponding to additional MOUSEEVENTF_LEFTUP, MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_LEFTUP events).

The reason for the Out of Bounds error is because I forgot to change the created buffer size from 2 to 5 on this line:
Code: [Select]
Win32.INPUT[] buffer = new Win32.INPUT[5];

2
I think he means to do this:
Code: [Select]
                   Win32.INPUT[] buffer = new Win32.INPUT[2];
                    buffer[0].type = Win32.INPUT_MOUSE;
                    buffer[0].mi.dx = (int) (warpedX * 65535.0f / screenWidth);
                    buffer[0].mi.dy = (int) (warpedY * 65535.0f / screenHeight);
                    buffer[0].mi.mouseData = 0;
                    buffer[0].mi.dwFlags = Win32.MOUSEEVENTF_ABSOLUTE | Win32.MOUSEEVENTF_MOVE;
                    buffer[0].mi.time = 0;
                    buffer[0].mi.dwExtraInfo = (IntPtr) 0;

                    buffer[1].type = Win32.INPUT_MOUSE;
                    buffer[1].mi.dx = 0;
                    buffer[1].mi.dy = 0;
                    buffer[1].mi.mouseData = 0;
                    buffer[1].mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
                    buffer[1].mi.time = 1;
                    buffer[1].mi.dwExtraInfo = (IntPtr) 0;

                    buffer[2].type = Win32.INPUT_MOUSE;
                    buffer[2].mi.dx = 0;
                    buffer[2].mi.dy = 0;
                    buffer[2].mi.mouseData = 0;
                    buffer[2].mi.dwFlags = MOUSEEVENTF_LEFTUP;
                    buffer[2].mi.time = 1;
                    buffer[2].mi.dwExtraInfo = (IntPtr) 0;

                    buffer[3].type = Win32.INPUT_MOUSE;
                    buffer[3].mi.dx = 0;
                    buffer[3].mi.dy = 0;
                    buffer[3].mi.mouseData = 0;
                    buffer[3].mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
                    buffer[3].mi.time = 1;
                    buffer[3].mi.dwExtraInfo = (IntPtr) 0;

                    buffer[4].type = Win32.INPUT_MOUSE;
                    buffer[4].mi.dx = 0;
                    buffer[4].mi.dy = 0;
                    buffer[4].mi.mouseData = 0;
                    buffer[4].mi.dwFlags = MOUSEEVENTF_LEFTUP;
                    buffer[4].mi.time = 1;
                    buffer[4].mi.dwExtraInfo = (IntPtr) 0;

                    Win32.SendInput (5, buffer, Marshal.SizeOf (buffer[0]));
Note that on the last line, the number of inputs has changed from 2 to 5.

3
Here's how this guy does it ( http://www.codeproject.com/KB/cs/Auto_Clicker_Bar.aspx , code is in MainForm.cs):

Code: [Select]
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern void mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);

[DllImport("user32")]
public static extern int SetCursorPos(int x, int y);

private const int MOUSEEVENTF_LEFTDOWN = 0x0002; /* left button down */
private const int MOUSEEVENTF_LEFTUP = 0x0004; /* left button up */

SetCursorPos(X, Y);
Thread.Sleep(100);
mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
Thread.Sleep(100);
mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);

4
Ok, now I'm confused. I thought the problem was that each Wiimote could only see half of the screen?

Or are you saying that you've got it figured out now?
EDIT: Sorry, my mistake. I thought I was replying to the original poster (I don't use forums very often).

EDIT:
@ujs: Are you talking about a situation where each Wiimote can only see half the screen (as the OP is dealing with), or with using multiple Wiimotes for redundancy, in case the person using it is blocking one of them (like Smoothboard does)?
And slightly off topic... when I last messed with Johnny Lee's whiteboard, it was a little jaggy due to the low camera resolution. I guess you're using a smoothing algorithm or something? I would be inclined to want to use as much data as available to (hopefully) improve resolution.

5
I suspect you need some kind of pause between the sending of the click commands. Not sure how to actually accomplish this though (Thread.Sleep maybe? but that blocks the thread...).

There has been a rather long discussion of syncing to an inaccessible Wiimote here: http://www.wiimoteproject.com/project-ideas/syncing-with-a-permanently-mounted-wiimote/

6
The wireless nunchuks seem to work differently from the regular nunchucks, and it seems that so far no one has been able to figure out how they work well enough to be able to interface with them. See: http://wiibrew.org/wiki/Wiimote/Extension_Controllers#Wireless_Nunchuks

7
Well, if you're already calibrating each Wiimote separately (with it's own set of 4 points on each half of the screen), then it should just be a matter of converting the units into a space for a single screen. For example (this is what I would try):
- Assume left quad is mapped to 0.0-1.0 coordinates, and the same for the right quad.
- Assuming you're using calibration points that are 0.1 inward from the edges, and this has already been compensated for (meaning the quad is expanded 0.1 outward from where the user marks the calibration points).
- If you position your inside 4 points so that they are 0.1 from the center line (for a 1.0 wide physical screen, this would be 0.05 from the left and right edges of each quad: 1.0 / 2 * 0.1), then both quads should effectively share the center line.
- So, you now have two quads calibrated separately (calibrate left 4 points for left Wiimote, then right 4 points for right Wiimote). At this point you could just do a bounds test to determine which side contains an IR point, and then map to a screen point.
- Example: With a 1024x768 screen, for a point in the left quad, you would take the point position (say 0.5), divide by two, and multiply the result by your screen size (0.5 / 2 * 1024 = 256; 1/4 of the way over just like we want). For a point in the right quad, just add 1 before before dividing ((1 + 0.5) / 2 * 1024 = 768).
- Now of course, since the Wiimote doesn't have perfect accuracy, there is going to be a little bit of error on the center line, and it might appear that the point is in both quads. If this turns out to be a problem (and I suspect it will), I would try just averaging the point if it falls within the bounds of both quads: take the position in one quad minus the position in the other quad (I'm talking projected final screen coordinates here), divide by 2 and add the first quad back in (vector averaging). It's not important if you're projecting a point with the warper matrix that is outside of a quad (like 1.1), it'll still map accurately (this is actually a property of the warper matrix that I'm relying on for my own project).

I'm not very familiar with Java and I don't really have time to figure out your code, so I'm afraid I can't help out much where the code is concerned.

8
(Assuming you're a programmer working on your own project, and not asking if some existing software can do this:)
- You might do something like an 8-point calibration, 4 points for each half of the screen and it's associated Wiimote (the Wiimotes should ideally be pointed in such a way that there is a little overlap in the middle).
- Then project both quads like they were individual whiteboards.
- Then, using your knowledge about how far away the 4 "inside" points should be from each other, use some additional calculations to "merge" the points calculated from both quads (perhaps doing some sort of weighted averaging on the overlapping areas to attempt to reduce errors when crossing from one side to the other).

One thing that does come to mind though, is how are you planning to position the Wiimotes? I'm guessing something like one on each side, at a fairly steep angle (to ensure they can still see the IR pen when you are in front of the screen), probably on lying on their side (to maximize vertical area)?

I have a similar situation with my light-gun project ( http://www.wiimoteproject.com/project-ideas/11-wiimote-lightgun-tracking/ ), except in my case there is only one Wiimote, and I have to figure out a way to "guess" missing points. I think your problem should be a lot easier to solve.

9
Project Ideas / MotionPlus Augmentation
« on: July 28, 2009, 08:24:22 AM »
Well, that answers that. I picked up a copy of Sports Report, and while the MotionPlus is cool and should open up a range of additional motion-sensing options (arm tracking comes to mind), it's not likely to help much with this.

Firstly, it definitely does not provide any real significant sort of directional aiming, at least of the sort needed for a real lightgun (which has to be based on the physical location of the screen). There is a good possibility that it could be used to provide some additional accuracy as I had suggested, but that leads to...

The second problem: the MotionPlus is designed to actually clip into the two slots on the bottom of the Wiimote, and therefore has two hooks sticking out that go into the slots. Without either A) Clipping off the hooks or B) Drilling holes into the bottom of the Nyko Perfect Shot, there isn't any way to attach it. While this isn't a huge problem for me personally (or, I suspect, many of you), the ultimate idea is to have a library that could be used by a more "average" user to play a light gun game on the computer. I guess the library could be designed with MotionPlus support, and just detect if one is plugged in or not and utilize it if so (assuming of course that it's even worthwhile to do so; it may turn out that the MotionPlus isn't accurate enough to provide any benefit). Something I'll have to think about down the road.

10
Project Ideas / REAL 1:1 Wiimote Lightgun Tracking
« on: July 26, 2009, 02:16:10 PM »
As I'm sure most of you are aware by now, the Wiimote is not capable of 1:1 light gun style tracking of the screen (ie, you can't point it at a specific location on the screen and calculate where exactly it is pointed and show a dot there, for instance). At least, not with the standard hardware setup.

This of course makes "light gun" games (Link's Crossbow Training, HOTD, Umbrella Chronicles, The Conduit, etc) rather un-lightgun like. You can't, for example, use the Nyko Perfect Shot (it's hard to be very accurate with a Wiimote by itself), point it at the screen, and have the cursor track to the physical screen location you're pointing at. It is only capable of tracking relative to the sensor bar, which, though it can be mitigated slightly by providing lots of configuration settings (eg, The Conduit), is still very sub-optimal.

I've figured out how to do 1:1 mapping using two sensor bars (one above and one below the TV) and the Wiimote's ability to track 4 IR points to use them to define a 3D plane, and then map the aiming point to the physical location on the screen. I can fairly accurately hit a 1-2 inch target on a 42 inch LCD from about 10 feet using a slightly modified Nyko Perfect Shot (a piece of paper has been added to the front to provide a front sight).

There are still several problems to be mitigated, but before I spend more time trying to work them out, I would like to be sure I'm not duplicating someone else's efforts. I have Googled around quite a bit, and have not found anything like this (the closest being someone with an HL2 mod designed to use vertical-standing IR bars in combination with a projector pointed at a wall; unfortunately I haven't been able to find it again so I can't provide a link). What I'm working on is of more practical application for the average user, since all you need is a single extra sensor bar (the Nyko Wireless bars work great) to be placed opposite of your regular sensor bar.

I would like to know if anyone is aware of an existing project that does this? If you know of something, please let me know!


Now, in the event that this is actually original work, I'll explain what I'm doing in a little more detail, and list some of the problems. Please let me know if this something that interests you, so I can get an idea of how useful something like this would be to the community.

(Introduction)
Q: Why doesn't the Wii already provide 1:1 screen tracking?
A: Because the included sensor bar only provides two IR tracking points. This is sufficient to provide distance, rotation, and relative position. But you need 3 points to define a 3D plane. With only 2 points, it's impossible to tell whether the sensor bar is becoming smaller because you are moving away from it, or because you are stepping sideways and looking at it from an angle (due to perspective foreshortening, the distance between the two points becomes smaller, but without a third reference, it's not possible to tell if this is because you are moving away or to the side).
Q: What about the Wii MotionPlus?
A: We'll probably know by next week (after we've had time to play with Wii Sports Resort... why did they decide to release that on a Sunday?). Right now I think it's safe to say it'll make good sword-fighting games possible, but whether it's accurate enough to map to a screen position? I can't say I'm holding my breath (it's designed to improve angular rotation response, not provide physical positional mapping for objects beyond your body). That said, it may be possible to improve the accuracy of this light-gun technique by utilizing the MotionPlus (see Problems to be Mitigated).

It would be totally awesome if future Wii games could support this sort of light-gun mapping by offering a configuration option to "Enable Light-Gun Tracking with 2nd Sensor Bar". I don't really expect this to actually happen any time soon, due to the Wii only coming with one sensor bar, but one can dream, can't he? Till then, we could use it on the PC to make "real" light-gun games, or mod existing games to provide light-gun style controls.

(How this project works)
As mentioned above, you cannot determine 3D plane from 2 points. But you can do it with three points. Or four points (which is actually easier for our purposes, but also introduces some problems). Since the Wiimote is capable of tracking up to four IR points, this works out great for us. All we need is a second sensor bar, and we can define a 3D plane!

So, by putting one sensor bar above the TV and another below, we can define the plane that the screen exists on. The resulting 4 IR points create a quad that can be then be mapped to screen space (I'm using Johnny Lee Chung's Warper.cs class from his Wiimote Whiteboard demo for this at the moment; I don't know enough fancy math to do it myself). Of course, you can't map the four points to the four corners of the screen (which is the way the Wiimote Whiteboard works). So you have to perform a second calibration mapping step, whereby you indicate four points on the corners of your screen which are then mapped relative to the 4 IR points, and finally turned into screen coordinates. (Sorry if I'm not being real clear here.)

So, long story short, you put a sensor bar above and below your TV, shoot a point in each corner, and you have 1:1 light-gun tracking with your Wiimote! (Sadly, of course, it's not QUITE that simple... continue reading.)

(Problems to be mitigated)
Problem #1: The Wiimote's camera has a rather limited field of view. What if one or more of the IR points moves out of view?
Solution: This is the reason I mentioned that I'm standing 10 feet from the TV.
- If one point is lost, I think it should be reasonably possible to estimate the location of the missing fourth point using the remaining three (remember, we only need a minimum of three points to define a 3D plane).
- If two points are lost, it should still be possible to estimate the location of the remaining two based on their last known location, although with reduced accuracy. This will occur quite often, when pointing toward the top or sides of the screen while standing too close.
- If three points are lost, it may still be possible to estimate the other three based on their last known locations, but accuracy will start to suffer horribly. This will occur if pointing toward the corners of the screen while standing too close. Fortunately, you will likely point toward the corners the least often (mostly it'll be towards the top or sides), and will most likely not remain pointing toward the corners for extended periods of time while moving around the room.
- If all four points move out of view, there is not much we can do. It's probably safe to say you're not pointing the Wiimote at the TV; unless of course you're like 1 foot away or something (it might be possible to use the accelerometer and/or Wii MotionPlus to determine if this is the case).

Problem #2: Currently the calibration only holds up well if you remain standing in the same position as when you calibrated it. It does work from alternate angles, but accuracy begins to suffer (targeting was off by about 2 inches in the corner of the screen when I calibrated from the front, and then tried shooting from about 45 degrees to the side).
Solution: I believe this is because with four points, it's possible to define a creased plane instead of a perfectly flat plane, and thus you have to position your sensor bars very carefully. I believe this could be mitigated by averaging the normals of both triangles which make up the quad, and using that to define a perfect 3D plane, but I don't know how to do that. You also have to try and position them directly opposite each other vertically, or you get a skewed quad, which throws things off (I think it should be possible to adjust for this as well, but again, I don't know how).

Problem #3: Cursor wiggle.
Solution: The Wiimote's camera is not very high resolution, which, combined with the shakiness of your hand, results in a lot of cursor wiggling (which gets worse the further away you are from the IR points). This can be reduced with a smoothing routine (which I've already implemented), but it may be possible to use the accelerometer and/or MotionPlus to provide improved micro-accuracy. As I mentioned, I can fairly reliably hit a 2 inch target on a 42 inch screen from 10 feet as-is; if micro-accuracy could be improved and wiggle reduced this could probably be increased to 1/2 inch or less.

Problem #4: Lag.
Solution: As anyone who's played Link's Crossbow Training is probably aware, there is a slight, but noticeable delay when you swing the cursor from one side of the screen to the other, requiring you to wait a moment for the cursor to "catch up" before pulling the trigger in order to hit what you're aiming for. This seems to be inherent in the system (the Wii's IR sensitivity calibration screen exhibits the same lag), so it may not be possible to do anything about it. On the other hand, if the delay is caused by the amount of time required by the Wiimote to process the IR image (and not the Bluetooth connection or something), and other sensors (I'm thinking MotionPlus here) send data sooner, it may be possible to use that data to estimate the location of the cursor slightly sooner than the actual IR information is available, thereby reducing perceived lag.

And I'm sure there are more problems that I haven't thought of yet... but I think that covers the major ones.

I look forward to your feedback!

Pages: 1