人気記事

iPhone Swift

iphoneアプリで加速度センサーの値をリアルタイムにグラフ表示する

更新日:

iPhoneアプリで加速度センサーの値を取得する方法については多くの記事が見つかりましたが、リアルタイムに計測値をグラフ表示する方法についてはなかなか見つけられなかったので試行錯誤で作成してみました。

以下が動作結果です。

スマホを振ると加速度の値も変化しておりながらリアルタイムの表示ができました。

 

ソースコード


import UIKit
import CoreMotion
import Charts


class ViewController: UIViewController{
    
    let motionManager = CMMotionManager()
    
    // チャート
    var chartView1 = LineChartView()
    var chartView2 = LineChartView()
    var chartView3 = LineChartView()
    var dataEntries1 = [ChartDataEntry]()
    var dataEntries2 = [ChartDataEntry]()
    var dataEntries3 = [ChartDataEntry]()
    var xValue: Double = 8
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupViews()
        setupInitialDataEntries()
        setupChartData()
        
        //加速度値を取得
        motionManager.accelerometerUpdateInterval = 0.1
        motionManager.startAccelerometerUpdates(
            to:OperationQueue.current!,
            withHandler: {(accelData:CMAccelerometerData?,errorOC: Error?) in
                self.didUpdatedChartView1(yValue: (accelData?.acceleration.z)!)
                self.didUpdatedChartView2(yValue: (accelData?.acceleration.y)!)
                self.didUpdatedChartView3(yValue: (accelData?.acceleration.x)!)
        }
        )
    }
    
    
     override func viewDidAppear(_ animated: Bool) {
     super.viewDidAppear(animated)
     
     //Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(didUpdatedChartView), userInfo: nil, repeats: true)
     }
     
    
    
    func stopAccelerometer(){
        if(motionManager.isAccelerometerActive){
            motionManager.stopAccelerometerUpdates()
        }
    }
    
    
    func didUpdatedChartView1(yValue: Double) {
        let newDataEntry = ChartDataEntry(x: xValue,
                                          y: yValue)
        updateChartView1(with: newDataEntry, dataEntries: &dataEntries1)
        xValue += 1
    }
    
    func didUpdatedChartView2(yValue: Double) {
        let newDataEntry = ChartDataEntry(x: xValue,
                                          y: yValue)
        updateChartView2(with: newDataEntry, dataEntries: &dataEntries2)
        xValue += 1
    }
    
    func didUpdatedChartView3(yValue: Double) {
        let newDataEntry = ChartDataEntry(x: xValue,
                                          y: yValue)
        updateChartView3(with: newDataEntry, dataEntries: &dataEntries3)
        xValue += 1
    }
    
    
    func setupViews() {
        
        //z
        view.addSubview(chartView1)
        chartView1.translatesAutoresizingMaskIntoConstraints = false
        //chartView1.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        //chartView1.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
        chartView1.frame = CGRect(x: 0 ,y: (self.view.frame.height/2)+100,width: self.view.frame.width,height: 150)
        //chartView1.widthAnchor.constraint(equalToConstant: view.frame.width - 32).isActive = true
        //chartView1.heightAnchor.constraint(equalToConstant: 100).isActive = true
        chartView1.leftAxis.axisMaximum = 1.2 //y左軸最大値
        chartView1.leftAxis.axisMinimum = -1.2 //y左軸最小値
        chartView1.leftAxis.labelCount = 5 //y軸ラベルの表示数
        chartView1.leftAxis.drawTopYLabelEntryEnabled = true //y軸の最大値
        chartView1.rightAxis.enabled = false //y右軸を非表示
        chartView1.legend.enabled = true //凡例を表示
        
        //y
        view.addSubview(chartView2)
        chartView2.translatesAutoresizingMaskIntoConstraints = false
        chartView2.frame = CGRect(x: 0 ,y: (self.view.frame.height/2)-100,
                                  width: self.view.frame.width,height: 150)
        chartView2.leftAxis.axisMaximum = 1.2 //y左軸最大値
        chartView2.leftAxis.axisMinimum = -1.2 //y左軸最小値
        chartView2.leftAxis.labelCount = 5 //y軸ラベルの表示数
        chartView2.leftAxis.drawTopYLabelEntryEnabled = true //y軸の最大値
        chartView2.rightAxis.enabled = false //y右軸を非表示
        chartView2.legend.enabled = true //凡例を表示
        
        //x
        view.addSubview(chartView3)
        chartView3.translatesAutoresizingMaskIntoConstraints = false
        chartView3.frame = CGRect(x: 0 ,y: (self.view.frame.height/2)-250,width: self.view.frame.width,height: 150)
        chartView3.leftAxis.axisMaximum = 1.2 //y左軸最大値
        chartView3.leftAxis.axisMinimum = -1.2 //y左軸最小値
        chartView3.leftAxis.labelCount = 5 //y軸ラベルの表示数
        chartView3.leftAxis.drawTopYLabelEntryEnabled = true //y軸の最大値
        chartView3.rightAxis.enabled = false //y右軸を非表示
        chartView3.legend.enabled = true //凡例を表示
    }
    
    func setupInitialDataEntries() {
        (0..<Int(xValue)).forEach {
            let dataEntry = ChartDataEntry(x: Double($0), y: 0)
            dataEntries1.append(dataEntry)
            dataEntries2.append(dataEntry)
            dataEntries3.append(dataEntry)
        }
    }
    
    func setupChartData() {
        //z
        let chartDataSet1 = LineChartDataSet(entries: dataEntries1, label: "z-ac")
        chartDataSet1.drawCirclesEnabled = false
        chartDataSet1.setColor(NSUIColor.red)
        chartDataSet1.mode = .linear
        chartDataSet1.drawValuesEnabled = false
        
        let chartData1 = LineChartData(dataSet: chartDataSet1)
        chartView1.data = chartData1
        chartView1.xAxis.labelPosition = .bottom
        
        //y
        let chartDataSet2 = LineChartDataSet(entries: dataEntries2, label: "y-ac")
        chartDataSet2.drawCirclesEnabled = false
        chartDataSet2.setColor(NSUIColor.green)
        chartDataSet2.mode = .linear
        chartDataSet2.drawValuesEnabled = false
        
        let chartData2 = LineChartData(dataSet: chartDataSet2)
        chartView2.data = chartData2
        chartView2.xAxis.labelPosition = .bottom
        
        //x
        let chartDataSet3 = LineChartDataSet(entries: dataEntries3, label: "x-ac")
        chartDataSet3.drawCirclesEnabled = false
        chartDataSet3.setColor(NSUIColor.blue)
        chartDataSet3.mode = .linear
        chartDataSet3.drawValuesEnabled = false
        
        let chartData3 = LineChartData(dataSet: chartDataSet3)
        chartView3.data = chartData3
        chartView3.xAxis.labelPosition = .bottom
        
    }
    
    func updateChartView1(with newDataEntry: ChartDataEntry, dataEntries: inout [ChartDataEntry]) {

        dataEntries.append(newDataEntry)
        chartView1.data?.addEntry(newDataEntry, dataSetIndex: 0)
        
        chartView1.notifyDataSetChanged()
        chartView1.moveViewToX(newDataEntry.x)
    }
    
    func updateChartView2(with newDataEntry: ChartDataEntry, dataEntries: inout [ChartDataEntry]) {

        dataEntries.append(newDataEntry)
        chartView2.data?.addEntry(newDataEntry, dataSetIndex: 0)
        
        chartView2.notifyDataSetChanged()
        chartView2.moveViewToX(newDataEntry.x)
    }
    
    func updateChartView3(with newDataEntry: ChartDataEntry, dataEntries: inout [ChartDataEntry]) {

        dataEntries.append(newDataEntry)
        chartView3.data?.addEntry(newDataEntry, dataSetIndex: 0)
        
        chartView3.notifyDataSetChanged()
        chartView3.moveViewToX(newDataEntry.x)
    }
    
}

 

処理の流れ

(1) 折れ線チャートをインスタンス

var chartView1 = LineChartView()

 

(2)Viewに折れ線チャートを加える。

view.addSubview(chartView1)

以降に軸や凡例の表示について設定

 

(3) 加速度値を取得

例えば、x方向の加速度値は「accelData?.acceleration.x」に格納されます。

//加速度値を取得 motionManager.accelerometerUpdateInterval = 0.1 motionManager.startAccelerometerUpdates( to:OperationQueue.current!, withHandler: {(accelData:CMAccelerometerData?,errorOC: Error?) in self.didUpdatedChartView1(yValue: (accelData?.acceleration.z)!) self.didUpdatedChartView2(yValue: (accelData?.acceleration.y)!) self.didUpdatedChartView3(yValue: (accelData?.acceleration.x)!) } )

(4) グラフ表示するためにはChartDataEntryクラスに整形してあげる必要があります。整形したクラスを引数としてupdateChartView関数に渡します。
 
func didUpdatedChartView1(yValue: Double) {
        let newDataEntry = ChartDataEntry(x: xValue,
                                          y: yValue)
        updateChartView1(with: newDataEntry, dataEntries: &dataEntries1)
        xValue += 1
    }

 

(5) updateChartView関数で加速度値が格納されたChartDataEntryをcharView.dataに加えることでグラフ表示されます。
 
func updateChartView1(with newDataEntry: ChartDataEntry, dataEntries: inout [ChartDataEntry]) {
 
        dataEntries.append(newDataEntry)
        chartView1.data?.addEntry(newDataEntry, dataSetIndex: 0)
        
        chartView1.notifyDataSetChanged()
        chartView1.moveViewToX(newDataEntry.x)
    }
 
 
x,y,zの3方向のグラフを表示するのに今回は工夫もなく3回同じ関数を作っていますが、もっとスマートなやり方があるような気がしています。
 

 

以上。

 

 

 

-iPhone, Swift

Copyright© ITエンジニアへの転身 , 2024 All Rights Reserved Powered by STINGER.