How to count steps using an gyroscope? - iphone

Am developing an application to calculate the steps of the human while walking,
I did this using accelerometer but I found that it's not accurate.
So after googling this, I found that using GyroScope sensor is more accurate than the accelerometer.
Any help with a control that might do this as I didn't ever develop using GyroScope, Or a document to read more about GyroScope Sensor.
Thanks in advance for help.
-(void)addAcceleration:(UIAcceleration*)accel
{
x = accel.x;
y = accel.y;
z = accel.z;
}
-(NSString*)name
{
return #"You should not see this";
}
#end
#define kAccelerometerMinStep 5.02
#define kAccelerometerNoiseAttenuation 1.0
double Norm(double x, double y, double z)
{
return sqrt(x * x + y * y + z * z);
}
double Clamp(double v, double min, double max)
{
if(v > max)
return max;
else if(v < min)
return min;
else
return v;
}
// See http://en.wikipedia.org/wiki/Low-pass_filter for details low pass filtering
#implementation LowpassFilter
-(id)initWithSampleRate:(double)rate cutoffFrequency:(double)freq
{
self = [super init];
if(self != nil)
{
double dt = 1.0 / rate;
double RC = 1.0 / freq;
filterConstant = dt / (dt + RC);
}
return self;
}
-(void)addAcceleration:(UIAcceleration*)accel
{
double alpha = filterConstant;
if(adaptive)
{
double d = Clamp(fabs(Norm(x, y, z) - Norm(accel.x, accel.y, accel.z)) / kAccelerometerMinStep - 1.0, 0.0, 1.0);
alpha = (1.0 - d) * filterConstant / kAccelerometerNoiseAttenuation + d * filterConstant;
}
x = accel.x * alpha + x * (1.0 - alpha);
y = accel.y * alpha + y * (1.0 - alpha);
z = accel.z * alpha + z * (1.0 - alpha);
}
-(NSString*)name
{
return adaptive ? #"Adaptive Lowpass Filter" : #"Lowpass Filter";
}
#end
// See http://en.wikipedia.org/wiki/High-pass_filter for details on high pass filtering
#implementation HighpassFilter
-(id)initWithSampleRate:(double)rate cutoffFrequency:(double)freq
{
self = [super init];
if(self != nil)
{
double dt = 1.0 / rate;
double RC = 1.0 / freq;
filterConstant = RC / (dt + RC);
}
return self;
}
-(void)addAcceleration:(UIAcceleration*)accel
{
double alpha = filterConstant;
if(adaptive)
{
double d = Clamp(fabs(Norm(x, y, z) - Norm(accel.x, accel.y, accel.z)) / kAccelerometerMinStep - 1.0, 0.0, 1.0);
alpha = d * filterConstant / kAccelerometerNoiseAttenuation + (1.0 - d) * filterConstant;
}
x = alpha * (x + accel.x - lastX);
y = alpha * (y + accel.y - lastY);
z = alpha * (z + accel.z - lastZ);
lastX = accel.x;
lastY = accel.y;
lastZ = accel.z;
}
-(NSString*)name
{
return adaptive ? #"Adaptive Highpass Filter" : #"Highpass Filter";
}

Use CoreMotion FrameWork.
#import <CoreMotion/CoreMotion.h>
self.motionManager = [[CMMotionManager alloc] init];
//Gyroscope
if([self.motionManager isGyroAvailable])
{
/* Start the gyroscope if it is not active already */
if([self.motionManager isGyroActive] == NO)
{
/* Update us 2 times a second */
[self.motionManager setGyroUpdateInterval:1.0f / 2.0f];
/* Add on a handler block object */
/* Receive the gyroscope data on this block */
[self.motionManager startGyroUpdatesToQueue:[NSOperationQueue mainQueue]
withHandler:^(CMGyroData *gyroData, NSError *error)
{
NSString *x = [[NSString alloc] initWithFormat:#"%.02f",gyroData.rotationRate.x];
self.gyro_xaxis.text = x;
NSString *y = [[NSString alloc] initWithFormat:#"%.02f",gyroData.rotationRate.y];
self.gyro_yaxis.text = y;
NSString *z = [[NSString alloc] initWithFormat:#"%.02f",gyroData.rotationRate.z];
self.gyro_zaxis.text = z;
}];
}
}
else
{
NSLog(#"Gyroscope not Available!");
}
Read this: http://developer.apple.com/library/ios/#documentation/EventHandling/Conceptual/EventHandlingiPhoneOS/Introduction/Introduction.html
Need to use two classes: CMGyrodata and CMMotionManager
Related to your question: How to count steps using an Accelerometer?
Read that, will be a good starting point...
Hope this helps...

On an Android device, I was able to use the accelerometer to count steps without much problem, see my answer here.

Related

cut a sprite sheet on cocos2d for animation

I want to cut a sprite in 6 equivalent parts just with one image, a .png file which I found on the web, no with texturepacker, (the image below by example)
I can take other way, but I want to know if I can do that. any one haves idea?
I'll revise my answer if this isn't what you were asking about, but I think you are asking how to 'manually run an animation' using a spritesheet without a plist.
Here's one way. It would be better if you encapsulated this into it's own class, but this can push you in the right direction I think:
ManualAnimationTest.h
#interface ManualAnimationTest : CCLayer
{
CCSprite *animatedSprite;
int x,y;
float animatedSpriteWidth, animatedSpriteHeight;
int animatedSpriteColumns, animatedSpriteRows;
}
#end
ManualAnimationTest.m
#import "ManualAnimationTest.h"
#implementation ManualAnimationTest
-(id) init
{
if( (self=[super init]))
{
CGSize s = [CCDirector sharedDirector].winSize;
x = 0;
y = 0;
animatedSpriteColumns = 3;
animatedSpriteRows = 2;
animatedSpriteWidth = 95.0f;
animatedSpriteHeight = 125.0f;
animatedSprite = [CCSprite spriteWithFile:#"animal_animation.png" rect:CGRectMake(x * animatedSpriteWidth,y * animatedSpriteHeight,animatedSpriteWidth,animatedSpriteHeight)];
[self addChild:animatedSprite];
[animatedSprite setPosition:ccp(s.width / 2.0f, s.height / 2.0f)];
[self schedule:#selector(animateAnimatedSprite) interval:0.5f];
}
return self;
}
-(void) animateAnimatedSprite
{
[animatedSprite setTextureRect:CGRectMake(x * animatedSpriteWidth, y * animatedSpriteHeight, animatedSpriteWidth, animatedSpriteHeight)];
x +=1;
if(x > (animatedSpriteColumns - 1))
{
x = 0;
y +=1;
}
if(y > (animatedSpriteRows - 1))
{
y = 0;
}
}
#end

Can I have a UICollectionViewFlowLayout with scrollDirection different from layout direction?

The UICollectionViewFlowLayout is great, however, I want it tweaked slightly so that the scrollDirection is different from the layout direction. Examples of what I'd like is the springboard home screen or the emoji keyboards where you can swipe left/right, but the cells are laid out left to right, top to bottom (instead of top to bottom, left to right as they are with the UICollectionViewFlowLayout with scrollDirection set to horizontal). Anyone know how I can easily subclass the FlowLayout to make this change? I'm disappointed they don't have a layoutDirection in addition to scrollDirection on the UICollectionViewFlowLayout object :(
#rdelmar I implemented something similar to your solution, and that works (not as elegant as I'd like), but I noticed that occasionally items disappear from the collection unless re-drawn, which is why I didn't accept the answer. Here is what I ended up with:
#interface UICollectionViewPagedFlowLayout : UICollectionViewFlowLayout
#property int width;
#property int height;
#end
#implementation UICollectionViewPagedFlowLayout
#warning MINOR BUG: sometimes symbols disappear
- (CGSize)collectionViewContentSize {
CGSize size = [super collectionViewContentSize];
// make sure it's wide enough to cover all the objects
size.width = self.collectionView.bounds.size.width * [self.collectionView numberOfSections];
return size;
}
- (NSArray*) layoutAttributesForElementsInRect:(CGRect)rect {
NSArray *array = [super layoutAttributesForElementsInRect:rect];
CGRect visibleRect;
visibleRect.origin = self.collectionView.contentOffset;
visibleRect.size = self.collectionView.bounds.size;
for (UICollectionViewLayoutAttributes* attributes in array) {
if (CGRectIntersectsRect(attributes.frame, rect)) {
// see which section this is in
CGRect configurableRect = UIEdgeInsetsInsetRect(visibleRect, self.sectionInset);
int horizontalIndex = attributes.indexPath.row % self.width;
int verticalIndex = attributes.indexPath.row / self.width;
double xspace = (configurableRect.size.width - self.width * self.itemSize.width) / self.width;
double yspace = (configurableRect.size.height - self.height * self.itemSize.height) / self.height;
attributes.center = CGPointMake(attributes.indexPath.section * visibleRect.size.width + self.sectionInset.left + (self.itemSize.width + xspace) * horizontalIndex + self.itemSize.width / 2, self.sectionInset.top + (self.itemSize.height + yspace) * verticalIndex + self.itemSize.height / 2);
}
}
return array;
}
#end
IIRC, exactly this is demonstrated in the WWDC 2012 sessions on UICollectionView.
I don't know about easily, depends on your definition I guess. I made a project where I had the layout that's close to what you're looking for. This lays out the rows horizontally, left to right, top to bottom. My data source was an array of arrays, where each subarray provided the data for one line.
#import "SimpleHorizontalLayout.h" // subclass of UICollectionViewFlowLayout
#define kItemSize 60
#implementation SimpleHorizontalLayout
-(CGSize)collectionViewContentSize {
NSInteger xSize = [self.collectionView numberOfItemsInSection:0] * (kItemSize + 20); // the 20 is for spacing between cells.
NSInteger ySize = [self.collectionView numberOfSections] * (kItemSize + 20);
return CGSizeMake(xSize, ySize);
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)path {
UICollectionViewLayoutAttributes* attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:path];
attributes.size = CGSizeMake(kItemSize,kItemSize);
NSInteger xValue = kItemSize/2 + path.row * (kItemSize +20) ;
NSInteger yValue = kItemSize + path.section * (kItemSize +20);
attributes.center = CGPointMake(xValue, yValue);
return attributes;
}
-(NSArray*)layoutAttributesForElementsInRect:(CGRect)rect {
NSInteger minRow = (rect.origin.x > 0)? rect.origin.x/(kItemSize +20) : 0; // need to check because bounce gives negative values for x.
NSInteger maxRow = rect.size.width/(kItemSize +20) + minRow;
NSMutableArray* attributes = [NSMutableArray array];
for(NSInteger i=0 ; i < self.collectionView.numberOfSections; i++) {
for (NSInteger j=minRow ; j < maxRow; j++) {
NSIndexPath* indexPath = [NSIndexPath indexPathForItem:j inSection:i];
[attributes addObject:[self layoutAttributesForItemAtIndexPath:indexPath]];
}
}
return attributes;
}
Until Apple adds a simple flag to change the layout orientation on flow layouts, I ended up sub-classing. Some of the stuff is specific to my implementation, but it might help someone else:
#interface UICollectionViewPagedFlowLayout : UICollectionViewFlowLayout
#property int width;
#property int height;
#end
#implementation UICollectionViewPagedFlowLayout
#warning MINOR BUG: sometimes items disappear
- (CGSize)collectionViewContentSize {
CGSize size = [super collectionViewContentSize];
size.width = self.collectionView.bounds.size.width * [self.collectionView numberOfSections];
return size;
}
- (NSArray*) layoutAttributesForElementsInRect:(CGRect)rect {
NSArray *array = [super layoutAttributesForElementsInRect:rect];
CGRect visibleRect;
visibleRect.origin = self.collectionView.contentOffset;
visibleRect.size = self.collectionView.bounds.size;
for (UICollectionViewLayoutAttributes* attributes in array) {
if (CGRectIntersectsRect(attributes.frame, rect)) {
// see which section this is in
CGRect configurableRect = UIEdgeInsetsInsetRect(visibleRect, self.sectionInset);
int horizontalIndex = attributes.indexPath.row % self.width;
int verticalIndex = attributes.indexPath.row / self.width;
double xspace = (configurableRect.size.width - self.width * self.itemSize.width) / self.width;
double yspace = (configurableRect.size.height - self.height * self.itemSize.height) / self.height;
attributes.center = CGPointMake(attributes.indexPath.section * visibleRect.size.width + self.sectionInset.left + (self.itemSize.width + xspace) * horizontalIndex + self.itemSize.width / 2, self.sectionInset.top + (self.itemSize.height + yspace) * verticalIndex + self.itemSize.height / 2);
}
}
return array;
}
#end

Show UIImageView in a random position on the screen

I am developing a game that uses the gyroscope to keep enemies in relatively the same place, with the following code:
if([motionManager isGyroAvailable])
{
[motionManager setGyroUpdateInterval:0.05];
[motionManager startGyroUpdatesToQueue:[NSOperationQueue mainQueue]
withHandler:^(CMGyroData *gyroData, NSError *error)
{
valueX3 = gyroData.rotationRate.y* 50;
valueY3 = gyroData.rotationRate.x* 50;
int newX3 = (int)(enemyufoG.center.x +valueY3);
int newY3 = (int)(enemyufoG.center.y -valueX3);
CGPoint newCenter2 = CGPointMake(newX3, newY3);
enemyufoG.center = newCenter2;
valueX2 = gyroData.rotationRate.y* 50;
valueY2 = gyroData.rotationRate.x* 50;
int newX2 = (int)(enemyufoR.center.x +valueY2);
int newY2 = (int)(enemyufoR.center.y -valueX2);
CGPoint newCenter = CGPointMake(newX2, newY2);
enemyufoR.center = newCenter;
valueX = gyroData.rotationRate.y* 50;
valueY = gyroData.rotationRate.x* 50;
int newX = (int)(enemyAlien.center.x +valueY);
int newY = (int)(enemyAlien.center.y -valueX);
CGPoint newCenter3 = CGPointMake(newX, newY);
enemyAlien.center = newCenter3;
}];
}
Once you shoot an enemy that is in the crosshairs of the gun, it hides the UIImageView, then uses NSTimer to call a different method that shows it again. I would like to have the enemies reappear in random positions on the screen.
CGPoint pos = enemyAlien.center;
if ((pos.x > 254) && (pos.x < 304) && (pos.y > 140) && (pos.y < 160 && _ammoCount != 0))
{
enemyAlien.hidden = YES;
[dangerBar setProgress:dangerBar.progress-0.10];
_killCount = _killCount+3;
[killCountField setText: [NSString stringWithFormat:#"%d", _killCount]];
timer = [NSTimer scheduledTimerWithTimeInterval: 4.0
target: self
selector: #selector(showAlien)
userInfo: nil
repeats: NO];
}
- (void) showAlien {
enemyAlien.hidden = NO;
}
When I try and use enemyAlien.center = enemyAlien.center + arc4random()%100; above enemyAlien.hidden = NO, I get the following error:
'Invalid operands to binary expression ('CGPoint (aka 'struct CGPoint') and 'unsigned int').
You're trying to add an integer to a cgpoint.
try this.
enemyAlien.center = CGPointMake(enemyAlien.center.x + (arc4random()%100),enemyAlien.center.y + (arc4random()%100));
although this will only move the alien in a diagonal direction. You should probably change it to the following for a better experience.
enemyAlien.center = CGPointMake((arc4random()%SCREEN_WIDTH),(arc4random()%SCREEN_HEIGHT));
where SCREEN_WIDTH and SCREEN_HEIGHT are the dimensions of your playing field.

UIAccelerometer distance calculation

I have used the following code to calculate the distance when the device moved from one place to another.Is it correct or not please look at my code.
-(void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{
NSDate *now = [NSDate date];
NSTimeInterval intervalDate = [now timeIntervalSinceDate:now_prev];
sx = acceleration.x * kFilteringFactor + sx * (1.0 - kFilteringFactor);
sy = acceleration.y * kFilteringFactor + sy * (1.0 - kFilteringFactor);
sz = acceleration.z * kFilteringFactor + sz * (1.0 - kFilteringFactor);
[xLabel setText:[NSString stringWithFormat:#"%.2f",sx]];
[yLabel setText:[NSString stringWithFormat:#"%.2f",sy]];
[zLabel setText:[NSString stringWithFormat:#"%.2f",sz]];
float aValue = sqrtf(sx*sx+sy*sy+sz*sz);
[gLabel setText:[NSString stringWithFormat:#"%.2f g",aValue]];
velX += (sx * intervalDate);
distX += (velX * intervalDate);
velY += (sy * intervalDate);
distY += (velY * intervalDate);
velZ += (sz * intervalDate);
distZ += (velZ * intervalDate);
float distance = sqrtf(distX*distX+distY*distY+distZ*distZ);
[distanceLabel setText:[NSString stringWithFormat:#"%.2f",distance*0.0006213f]];
now_prev = [now retain];
}
There are a lot of reasons why trying to get distance from accelerator data is going to be terribly inefficient.
In order to keep track of your initial location, you need to continuously integrate all acceleration values into a vector, and preferably at a very high sampling rate (big gaps in your calculations will lead to inaccuracies)
The method itself isn't terribly hard to figure out (or google for that matter) ;
This question explains how to do the maths and pseudocode for such an integration approach

Custom mapping functionality within iPhone App using CoreLocation

I'm developing some custom mapping functionality in my App and have hit a stumbling block.
This map is for a known area (i.e. I know the exact latitude / longitude of top left and bottom right corners) and I have a graphic image of the area, to scale, which I use as the background (I don't want to use an MKMapView for this).
I'm using CoreLocation to provide me with my latitude / longitude and am trying to translate these 'real' coords into a spot on the custom map.
One thing to note is that my custom map (which is displayed in a UIScrollView) is rotated from north by a certain angle (i.e. the top of the custom map does not equate to north), therefore, I need to translate/rotate all coords returned via CoreLocation.
I am using the following code to try and do this:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
CLLocation *pTL = [self rotateLocation:self.topLeftCorner
aboutLocation:newLocation];
CLLocation *pBR = [self rotateLocation:self.bottomRightCorner
aboutLocation:newLocation];
double mapCoordX = ((pTL.coordinate.longitude - newLocation.coordinate.longitude) / (pTL.coordinate.longitude - pBR.coordinate.longitude)) * imageWidth;
double mapCoordY = ((pTL.coordinate.latitude - newLocation.coordinate.latitude) / (pTL.coordinate.latitude - pBR.coordinate.latitude)) * imageHeight;
if ((mapCoordX >= -self.beaconImage.frame.size.width && mapCoordX <= imageWidth + self.beaconImage.frame.size.width) && (mapCoordY >= -self.beaconImage.frame.size.height && mapCoordY <= imageHeight + self.beaconImage.frame.size.height)) {
self.beaconImage.center = CGPointMake(mapCoordX, mapCoordY);
self.beaconImage.hidden = NO;
} else {
UIAlertView *av = [[UIAlertView alloc]
initWithTitle:nil
message:#"You're not within the boundaries of the map"
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[av show];
[av release];
self.beaconImage.hidden = YES;
}
}
- (CLLocation *)rotateLocation:(CLLocation *)rotationLocation aboutLocation:(CLLocation *)baseLocation {
double mapLatitudeOffset = topLeftCorner.coordinate.latitude + bottomRightCorner.coordinate.latitude;
double mapLongitudeOffset = topLeftCorner.coordinate.longitude - bottomRightCorner.coordinate.longitude;
double mapOffsetAngle = 0;
if (mapLongitudeOffset == 0 && mapLatitudeOffset == 0) {
mapOffsetAngle = 0;
} else if (mapLongitudeOffset >= 0) {
mapOffsetAngle = atan2(mapLongitudeOffset, mapLatitudeOffset);
} else {
mapOffsetAngle = -atan2(mapLongitudeOffset, mapLatitudeOffset) + M_PI;
}
double latitudeOffset = (rotationLocation.coordinate.latitude + (baseLocation.coordinate.latitude * -1));
double longitudeOffset = (rotationLocation.coordinate.longitude + (baseLocation.coordinate.longitude * -1));
double radius = sqrt(pow(latitudeOffset, 2) + pow(longitudeOffset, 2));
double theta = 0;
if (longitudeOffset == 0 && latitudeOffset == 0) {
theta = 0;
} else if (longitudeOffset >= 0) {
theta = atan2(longitudeOffset, latitudeOffset);
} else {
theta = -atan2(longitudeOffset, latitudeOffset) + M_PI;
}
double angularOffset = theta + mapOffsetAngle;
double latitudeRotate = radius * sin(angularOffset);
double longitudeRotate = radius * cos(angularOffset);
return [[[CLLocation alloc] initWithLatitude:baseLocation.coordinate.latitude + latitudeRotate longitude:baseLocation.coordinate.longitude + longitudeRotate] autorelease];
}
Unfortunately, the calculated values aren't correct, and so the beacon image I use to indicate my current position is showing in the wrong area of the map.
It seems like a straightforward problem, so what am I doing wrong?