福野泰介の一日一創 - create every day

みんなでつくる地域ICTクラブ、福井高専IT研究会と鯖江商工会議所あたらしもん好き勉強会

2018/10/12
#IchigoJam #IoT #VR #megane #swift #kosen #sabae 

福井高専電子情報工学科、1年後期から、いよいよプログラミングの授業スタート!
初回は IchigoJam を使って、自分のパソコンづくりとプログラミング入門。
ひとりずつはんだづけした後、エルチカ、かわくだりゲーム、10秒あてIoTゲームをペアでつくってコンピューターを操る感覚を掴んでもらいました。


はんだづけスタート!
自分のパソコンをまだもっていなかった学生も、ひとまず1台ゲット。


個性がでるはんだづけ、部品をまっすぐつけることにこだわる!


女子は髪をこがさないよう、注意!


できあがった IchigoJam S。すっきりシンプルになったこともあってトラブルも減って1コマ、90分ちょっとでほぼ全員完成!


ペアプログラミングスタイルで、プログラミング入門&IoTはじめのいっぽスタート!

IchigoJam かわくだりゲームの改造版(点数追加、スペースキーでボム、時間でだんだん速くなる)

10 CLS:X=15:CLT 20 LC X,5:?"O" 30 LC RND(32),23:?"*" 35 WAIT 6-TICK()/180 36 X=X-BTN(28)+BTN(29) 37 X=X&31 38 IF BTN(32) CLS 40 IF SCR(X,5) GOTO20

IchigoJam BASIC リファレンスを見ながら、解読してみよう!
ネットでじっくり学ぶテキスト「IchigoJamプリント
ブラウザで動く、IchigoJam web もあるよ!
良い作品ができたら、Kidspod;や、電子工作マガジンに投稿しよう。
わからないことがあれば、IchigoJam-FAN (Facebook) か、#IchigoJam (Twitter) へどうぞ!


福井高専の電子情報工学科を選択した42名、楽しくプログラミング学んでいきましょう!
作ったIchigoJamは、実験でも使いますよ!
(現在福井高専は、1年生が混合学級をとっていますが、専門科目の時間は各クラスから集まって実施)


福井高専IT研究会に新1年生を勧誘!PCN鯖江にも新メンバー!


福井高専メディア研究会のラジオ番組新コーナー「OBさんいらっしゃい」に出演!
OB/OGというのは冗長なので、語源はともかくOBで統一する形でいきましょう。


ものづくりのまち鯖江ならではの、新基軸情報発信を目指す会!


体験しないとわからない、VR/MRの世界 at 鯖江商工会議所の新企画「あたらしもん好き勉強会#1」

アイデアディスカッション、その1「続きはリアルで!鯖江のVRと言えば?」

メガネを作っている職人視点VR(製造工程) コンサート映像VR(人形浄瑠璃、サンドーム) 歴史VR(近松門左衛門) 西山動物園(動物間近でみる) 鯖江の郷土料理のつくりかたVR動画(サバエドッグ) 加藤吉兵衛商店で酒造り見学、中松で飲む気分VR ドローン映像、上空から鯖江(鳥視点) 福鉄運転席 サバエドッグ視点 観光ガイドVR(自治体とお年寄りがネック?) 美術館・博物館の美術品を見せる

アイデアディスカッション、その2「ミライのメガネ」

カーナビ(人生ナビ) 年収見えるメガネ 共通の友達が見えるメガネ 自分との相性が見えるメガネ(好感度) 料理のカロリー見える(アレルギー) スイカの糖度判定(果物) 透けるメガネ 寿命が見えるメガネ(デスノート) 財布替わりになるメガネ 見るだけで最安値が見えるメガネ(レビュー) 店の評価が見えるメガネ リアルなマリオブラザーズ(クリボーがでてくる) 武家屋敷復元 メガネがスマホの替わりになる(事故率下がる、猫背が治る?) 組み立て手順をガイドする

もりあがった、MR、電脳メガネ。
オープンソースな電脳メガネアプリをSwift4.2に対応し、ちょっとバージョンアップ。
「Megane」src on GitHub

世界が印刷物風に見えるメガネと


世界がステンドグラス風に見えるメガネを追加!

メガネのまち鯖江だけに、IT研究会でもOculusなどメガネ系に関心ある学生多いかも!?
今度持っていくのでお楽しみに!

見る人すべてがネコミミになるメガネ「nekomimiworld」の作り方、一番好きな三角関数は何ですか?

2018/07/14
#swift #megane 

見る人すべてがめがねをかけて見える「meganeworld
MR(Mixed Reality)による近未来、たった800円のスマホVRで開発可能です。

見えている人が「かわいい」と、人はやさしくなれるかも?

安直な「かわいい」の実現「ネコミミ」を見ている人側で勝手に付加するMRアプリを作ってみましょう。

Hana道場、若宮さんと学ぶIoTとIchigoJamプログラミングと地域フィールドラボ第5期スタート!」より

GitHubにあるiPhone用、プログラミング言語Swiftで書かれた、「meganeworld - megane」 にネコミミ表示を足します。 右目位置、左目位置を、顔認識APIから受け取って、三角関数を使って角度を求め、ネコミミ位置を計算し、黒の三角形を描画!(プログラム全文はGitHubで

// nekomimi let dx = left.x - right.x let dy = left.y - right.y let len = sqrt(dx * dx + dy * dy) let th = atan2(dy, dx); let ox = [ right.x, left.x ] let oy = [ right.y, left.y ] for n in 0...1 { let dir = CGFloat(n == 0 ? 1 : -1) let deg0 = 90 + 20 * dir let th0 = th + CGFloat.pi / 180 * CGFloat(deg0) let len0 = len * 1.3 let x0 = ox[n] + cos(th0) * len0 let y0 = oy[n] + sin(th0) * len0 g.beginPath() g.setLineWidth(4) g.setFillColor(UIColor.white.cgColor) let th1 = th0 + CGFloat.pi / 180 * 20 * dir let len1 = len * 0.4 let x1 = x0 + cos(th1) * len1 let y1 = y0 + sin(th1) * len1 g.move(to:CGPoint(x:x1, y:y1)) let th2 = th1 + CGFloat.pi / 180 * 120 * dir let len2 = len * 0.6 let x2 = x0 + cos(th2) * len2 let y2 = y0 + sin(th2) * len2 g.addLine(to:CGPoint(x:x2, y:y2)) let th3 = th1 - CGFloat.pi / 180 * 120 * dir let len3 = len * 0.6 let x3 = x0 + cos(th3) * len3 let y3 = y0 + sin(th3) * len3 g.addLine(to:CGPoint(x:x3, y:y3)) g.addLine(to:CGPoint(x:x1, y:y1)) g.fillPath() }

MSX BASICの三角関数であれこれ遊んだ小中学生時代。
シューティングゲームや、優雅な動き、3Dプログラミングなど、よく出てくるので遊びながら覚えちゃいます。
一番好きな三角関数は、atan2こと、yとxをパラメータとして渡す逆タンジェント(Arctangent)
atan(y / x) として使うため、引数の順序も普通じゃない atan2(y, x) というのもお気に入り。

Swiftでプログラミングしていて驚いたコンパイルエラー
「Expression was too complex to be solved in reasonable time; ...」
IchigoJamのも計算用のスタックに多くのメモリを使えないため「Too complex」というエラーがありますが、現代言語でも目にかかるとは!

IchigoJamと同様、式を分割するか、型の明確化で対応が可能しましょう。

links
- Ichigojam Basicで円を描く – chobitte
- 2015-08-26 [IchigoJam]円を描く - SHIROのモバイル日記
- 三角関数が好き sin cos tan

Welcome to Megane World! めがねxIT at めがねフェス2018

2018/06/08
#megane #vr #swift 

Welcome to Megane World! めがねをかけないと損する時代は、もうまもなく!

一足先にスマホMRで体験、見えている人、全員が赤いメガネをかける世界。


6/9-10の2日間はステキなメガネに会える「めがねフェス2018
ステージ、グルメ、ショップ、ワークショップなど、イベント盛りだくさん!隣のめがね会館へもどうぞ!


オススメは800円から買えちゃう、各種スマホVR、ぜひ試着してお気に入りのVRを手に入れてください。
一段上のVR体験、Oculus Go も展示!
発売開始から3分で完売 Oculus Go中国国内モデル、入荷待ちは5万人以上 | Mogura VR - 国内外のVR/AR/MR最新情報


めがねxIT」ブースで体験できるメガネアプリ開発者は鯖江在住の現役高校生プログラマー!
ITの基本、プログラミングを子供も大人も学べる格安パソコン「IchigoJam」の体験コーナーもあります。限定品の販売も!?


めがねのまちさばえ!

links
- めがねフェス2018

QRコードが読め、ズームでき、写真が撮れるメガネ開発!オープンソースなスマホMR in Swift4

2018/05/26
#swift #megane 

外カメラ x スマホVR = デジタルメガネ

JSで手軽なWebMeganeもオススメながら、iPhoneネイティブアプリとして作ると、顔認識や、QRコード認識などが高速で楽しい!

リアルタイムにQRコード内容をデコードして、視界をオーバーレイ(上書き)するメガネができた。
megane - qrdetector on GitHub」 Swift4で実装

ウィンクシャッターが便利だったGoogle Glassのように、手軽に写真撮影もついでに実装。
ボリュームダウンキーで、シャッター(初回のみダイアログがでるので、VRにする前に押しておこう)
ボリュームアップキーで、視界をズームすることもできる(現在は、1920x1080の画像をデジタルズーム)

こちら「オタマートで売ってるVRゴーグル」の一番安いもの。ボリュームアップダウンが上からアクセスできる!
ボリュームアップダウンキーのついたイヤホンを接続すると、手元でも操作できるようになって便利。
デジタルメガネなUXづくり、いろいろ試していきましょう。

鯖江の道の駅、西山公園前のバス停。日本語表記しかない標識にQRコードをつけておけば、リアルタイムに見ている人の母国語に変換できそう。

Let's hack your sight!

AppDelegate.swift

import UIKit @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { return true } func applicationWillResignActive(_ application: UIApplication) { } func applicationDidEnterBackground(_ application: UIApplication) { NotificationCenter.default.post(name: NSNotification.Name(rawValue: "applicationDidEnterBackground"), object: nil) } func applicationWillEnterForeground(_ application: UIApplication) { NotificationCenter.default.post(name: NSNotification.Name(rawValue: "applicationWillEnterForeground"), object: nil) } func applicationDidBecomeActive(_ application: UIApplication) { } func applicationWillTerminate(_ application: UIApplication) { } }

ViewController.swift

// // ViewController.swift // megane, QR code detector glass with VR goggle // // CC BY taisukef on 2018/05/24. // http://fukuno.jig.jp/2133 // import UIKit import AVFoundation import MediaPlayer class ViewController: UIViewController, AVCaptureVideoDataOutputSampleBufferDelegate { override func viewDidLoad() { super.viewDidLoad() self.view.backgroundColor = UIColor.black self.imageView1 = UIImageView() self.imageView2 = UIImageView() let w = self.view.frame.width let h = self.view.frame.height let w2 = w / 2 let h2 = w2 * 1080 / 1920 let y = (h - h2) / 2 self.imageView1.frame = CGRect(x:0, y:y, width:w2, height:h2) self.imageView2.frame = CGRect(x:self.view.frame.width / 2, y:y, width:w2, height:h2) self.view.addSubview(self.imageView1) self.view.addSubview(self.imageView2) self.initNotificationsFromAppDelegate() } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } var input:AVCaptureDeviceInput! var output:AVCaptureVideoDataOutput! var session:AVCaptureSession! var camera:AVCaptureDevice! var imageView1:UIImageView! var imageView2:UIImageView! override func viewWillAppear(_ animated: Bool) { self.configureCamera() self.listenVolumeButton() } // notifications foreground and background func initNotificationsFromAppDelegate() { NotificationCenter.default.addObserver(self, selector: #selector(type(of: self).viewWillEnterForeground(notification:)), name: NSNotification.Name(rawValue: "applicationWillEnterForeground"), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(type(of: self).viewDidEnterBackground(notification:)), name: NSNotification.Name(rawValue: "applicationDidEnterBackground"), object: nil) } @objc func viewWillEnterForeground(notification: NSNotification?) { print("foreground") self.listenVolumeButton() } @objc func viewDidEnterBackground(notification: NSNotification?) { print("background") self.removeVolumeButton() } // override func viewDidDisappear(_ animated: Bool) { session.stopRunning() for output in session.outputs { session.removeOutput(output) } for input in session.inputs { session.removeInput(input) } session = nil camera = nil } let DETECT_QRCODE = false func configureCamera() { session = AVCaptureSession() // iPhone Xで実験 //session.sessionPreset = AVCaptureSession.Preset.cif352x288 // 34% 荒い //session.sessionPreset = AVCaptureSession.Preset.vga640x480 // 47% 4:3 なかなかきれい //session.sessionPreset = AVCaptureSession.Preset.iFrame1280x720 // CPU50% 16:9 かわらない? //session.sessionPreset = AVCaptureSession.Preset.hd1280x720 // CPU50% 16:9 きれい session.sessionPreset = AVCaptureSession.Preset.hd1920x1080 // CPU88% 16:9 かわらない? iPhone6でもQRcode offならOK! //session.sessionPreset = AVCaptureSession.Preset.hd4K3840x2160 // CPU93% 16:9 かわらない? QRcode offなら実用的 camera = AVCaptureDevice.default( AVCaptureDevice.DeviceType.builtInWideAngleCamera, for: AVMediaType.video, position: .back) // position: .front do { input = try AVCaptureDeviceInput(device: camera) } catch let error as NSError { print(error) } if (session.canAddInput(input)) { session.addInput(input) } output = AVCaptureVideoDataOutput() // AVCapturePhotoOutput() 写真用 output?.videoSettings = [kCVPixelBufferPixelFormatTypeKey as AnyHashable : Int(kCVPixelFormatType_32BGRA)] as! [String : Any] let queue:DispatchQueue = DispatchQueue(label: "myqueue", attributes: .concurrent) output.setSampleBufferDelegate(self, queue: queue) output.alwaysDiscardsLateVideoFrames = true // 間に合わないものは処理しない if (session.canAddOutput(output)) { session.addOutput(output) } session.startRunning() } var zoom:CGFloat = 1.0 func captureOutput(_: AVCaptureOutput, didOutput: CMSampleBuffer, from: AVCaptureConnection) { // from.videoOrientation = .portrait //デバイスの向きを設定、縦の時 from.videoOrientation = .landscapeLeft //デバイスの向きを設定、landscape left の時 DispatchQueue.main.sync(execute: { var image = self.imageFromSampleBuffer(sampleBuffer: didOutput) image = resizeImage(image: image, ratio: zoom) if DETECT_QRCODE { image = drawQR(image: image) } self.imageView1.image = image self.imageView2.image = image }) } func resizeImage(image: UIImage, ratio: CGFloat) -> UIImage { if ratio == 1.0 { return image } let iw = image.size.width / ratio let ih = image.size.height / ratio let size = CGSize(width: iw, height: ih) UIGraphicsBeginImageContext(size) image.draw(in: CGRect(origin: CGPoint(x:-(image.size.width - iw) / 2, y:-(image.size.height - ih) / 2), size: image.size)) let resimage = UIGraphicsGetImageFromCurrentImageContext()! UIGraphicsEndImageContext() return resimage } func drawQR(image: UIImage) -> UIImage { UIGraphicsBeginImageContext(image.size) let rect = CGRect(x:0, y:0, width:image.size.width, height:image.size.height) image.draw(in: rect) let g = UIGraphicsGetCurrentContext()! g.setStrokeColor(UIColor.white.cgColor) g.setLineWidth(1) let font = UIFont.boldSystemFont(ofSize: 14) let textStyle = NSMutableParagraphStyle.default.mutableCopy() as! NSMutableParagraphStyle let textFontAttributes = [ NSAttributedStringKey.font: font, NSAttributedStringKey.foregroundColor: UIColor.black, NSAttributedStringKey.paragraphStyle: textStyle ] // 顔認識もおもしろい // let detector : CIDetector = CIDetector(ofType: CIDetectorTypeFace, context: nil, options:[CIDetectorAccuracy: CIDetectorAccuracyLow] )! // 読める四角は今のところひとつだけ // let detector : CIDetector = CIDetector(ofType: CIDetectorTypeRectangle, context: nil, options:[CIDetectorAccuracy: CIDetectorAccuracyHigh, CIDetectorAspectRatio: 1.0] )! let detector : CIDetector = CIDetector(ofType: CIDetectorTypeQRCode, context: nil, options:[CIDetectorAccuracy: CIDetectorAccuracyHigh] )! let features : NSArray = detector.features(in: CIImage(image: image)!) as NSArray if features.count > 0 { for feature in features as! [CIQRCodeFeature] { var rect: CGRect = (feature as AnyObject).bounds rect.origin.y = image.size.height - rect.origin.y - rect.size.height // QRコードを上書き! g.beginPath() g.setFillColor(UIColor.white.cgColor) g.addRect(rect) g.fillPath() feature.messageString?.draw(in: rect, withAttributes: textFontAttributes) } } let resimage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return resimage! } func imageFromSampleBuffer(sampleBuffer: CMSampleBuffer) -> UIImage { let imageBuffer: CVImageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)! CVPixelBufferLockBaseAddress(imageBuffer, CVPixelBufferLockFlags(rawValue: 0)) let baseAddress = CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 0) let bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer) let width = CVPixelBufferGetWidth(imageBuffer) let height = CVPixelBufferGetHeight(imageBuffer) let colorSpace = CGColorSpaceCreateDeviceRGB() let bitmapInfo = (CGBitmapInfo.byteOrder32Little.rawValue | CGImageAlphaInfo.premultipliedFirst.rawValue) let context = CGContext(data: baseAddress, width: width, height: height, bitsPerComponent: 8, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo) let imageRef = context!.makeImage() CVPixelBufferUnlockBaseAddress(imageBuffer, CVPixelBufferLockFlags(rawValue: 0)) return UIImage(cgImage: imageRef!) } // volume switch var initialVolume = 0.0 var volumeView: MPVolumeView? func listenVolumeButton() { volumeView = MPVolumeView(frame: CGRect(x:-3000, y:0, width:0, height:0)) view.addSubview(volumeView!) let audioSession = AVAudioSession.sharedInstance() do { try audioSession.setActive(true) let vol = audioSession.outputVolume initialVolume = Double(vol.description)! if initialVolume > 0.9 { initialVolume = 0.9 } else if initialVolume < 0.1 { initialVolume = 0.1 } } catch { print("error: \(error)") } audioSession.addObserver(self, forKeyPath: "outputVolume", options: NSKeyValueObservingOptions.new, context: nil) } func removeVolumeButton() { AVAudioSession.sharedInstance().removeObserver(self, forKeyPath: "outputVolume") volumeView?.removeFromSuperview() } override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { if keyPath == "outputVolume" { let volume = (change?[NSKeyValueChangeKey.newKey] as! NSNumber).floatValue let newVolume = Double(volume) if newVolume > initialVolume + 0.05 { if let view = volumeView?.subviews.first as? UISlider { // volume up pressed view.value = Float(initialVolume) if zoom < 12.0 { zoom *= 1.2 } else { zoom = 1.0 } print("zoom: \(zoom)") } } else if newVolume < initialVolume - 0.05 { if let view = volumeView?.subviews.first as? UISlider { // volume down pressed view.value = Float(initialVolume) /* if zoom > 1.0 { zoom /= 1.2 } */ if let image = self.imageView1.image { saveImage(image: image) print("save image") } } } } } // save private func saveImage(image: UIImage) { UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil) } }

megane - qrdetector on GitHub」 in Swift4

links
- WebMegane - your new digital sight / デジタルな視界 on iPhone Safari x VR goggles (JS、webアプリ版)

Swift4でつくるQRコードをリアルタイムに読むアプリ

2018/05/24
#swift #megane 

iPhoneの本当のおもしろさはプログラミングしないと分からない。
画像認識APIのひとつ、QRコード認識を使って、リアルタイムにQRコードが読めるアプリを作ってみました。

QRコードを認識すると、埋め込まれている文字として上書きします。
(QRコード生成アプリ qrmakeriPhone風スマホ画像素材使用)

Swift4で書く、QRコードの認識プログラムは簡単!カメラからの画像を CIDetector に渡すだけ。
画面内の複数のQRコードをまとめて認識してくれるのがおもしろい!

let detector : CIDetector = CIDetector(ofType: CIDetectorTypeQRCode, context: nil, options:[CIDetectorAccuracy: CIDetectorAccuracyHigh] )! let features : NSArray = detector.features(in: ciimage) as NSArray

まちの標識の先頭につけておき、その人が分かる文字にリアルタイムに、視界を上書きするメガネが簡単にできちゃいそうです。

現実とネットをつなぐインターフェイス、メガネ。
いよいよ実現が近づいてきました!

links
- WebMeganeでMR、JSで手軽に実現、外カメラ映像とCGをミックス!

すぐ作れる力で備える。一日一創のきっかけ、3.11 - Swift4で点字テーブルアプリ

2018/03/11
#swift #braille 

7年前の2011年、必要なものをすぐに作ることができなかった悔しさが、2012年の一日一創の原動力。
あのときには存在しなかったオープンデータが、今は日本中にある。
開発力を持った子供たちがどんどん誕生している。

久々にiPhoneネイティブアプリをSwiftで作ってみる。
Swift入門から3年、当時Swift2だったものはSwift4になっている。
時代に合わせてどんどん変わる言語を使うには、webと自ら学ぶ力、大事。

動作確認を兼ねて、点字を覚えるためのアプリを作成。
点字と書いた点字アイコン。

タップしたら、体表点字化させるなど、何か作ると、追加でいろいろ改造したくなる。


Xcodeの新規プロジェクト作成画面、"Argumented Reality App"を選ぶと、すぐにできちゃうARアプリ。

当初は有料でしか開発できなかったiPhoneアプリ、今は無料なのでMacとiPhoneを持っていれば子供でも気軽に開発可能。
[Xcode][iOS] 有料ライセンスなしでの実機インストール 全工程解説! | Developers.IO
あると楽しい、すぐ作れる力!

点字テーブルアプリのプログラム(ViewController.swift)

// // ViewController.swift // tenji1 // // Created by Taisuke Fukuno on 2018/03/12. in Swift4 // CC BY http://fukuno.jig.jp/ // import UIKit class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate { var tableView:UITableView! /* 2800 ⠀ ⠁ ⠂ ⠃ ⠄ ⠅ ⠆ ⠇ ⠈ ⠉ ⠊ ⠋ ⠌ ⠍ ⠎ ⠏ 2810 ⠐ ⠑ ⠒ ⠓ ⠔ ⠕ ⠖ ⠗ ⠘ ⠙ ⠚ ⠛ ⠜ ⠝ ⠞ ⠟ 2820 ⠠ ⠡ ⠢ ⠣ ⠤ ⠥ ⠦ ⠧ ⠨ ⠩ ⠪ ⠫ ⠬ ⠭ ⠮ ⠯ 2830 ⠰ ⠱ ⠲ ⠳ ⠴ ⠵ ⠶ ⠷ ⠸ ⠹ ⠺ ⠻ ⠼ ⠽ ⠾ ⠿ https://ja.wikipedia.org/wiki/%E7%82%B9%E5%AD%97 */ let sections = ["数字", "アルファベット", "ひらがな", "記号"] let data = [ ["1 ⠂", "2 ⠆", "3 ⠒", "4 ⠲", "5 ⠢", "6 ⠖", "7 ⠶", "8 ⠦", "9 ⠔", "0 ⠴" ], ["A ⠁", "B ⠃", "C ⠉", "D ⠙", "E ⠑", "F ⠋", "G ⠛", "H ⠓", "I ⠊", "J ⠚", "K ⠅", "L ⠇", "M ⠍ ", "N ⠝", "O ⠕", "P ⠏", "Q ⠟", "R ⠗", "S ⠎", "T ⠞", "U ⠥", "V ⠧", "W ⠺", "X ⠭", "Y ⠽", "Z ⠵" ], [ "あ ⠁", "い ⠃", "う ⠉", "え ⠖", "お ⠊", "か ⠡", "さ ⠱", "た ⠕", "な ⠅", "は ⠥", "ま ⠵", "や ⠌", "ら ⠑", "わ ⠄", "を ⠔", "ん ⠴" ], [ "数字 ⠼", "アルファベット(外字符) ⠰", "濁音符 ⠐", "半濁音符 ⠠", ] ] override func viewDidLoad() { super.viewDidLoad() tableView = UITableView() tableView.frame = view.frame tableView.delegate = self tableView.dataSource = self tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell") tableView.tableFooterView = UIView(frame: .zero) view.addSubview(tableView) } func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { return 40 // セクションヘッダの高さ } func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return 20 // セルの高さ } func numberOfSections(in tableView: UITableView) -> Int { return sections.count } func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { return sections[section] } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return data[section].count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) cell.textLabel?.text = data[indexPath.section][indexPath.row] //cell.accessoryType = .disclosureIndicator //cell.accessoryView = UISwitch() // スィッチ return cell } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { print(indexPath) // セルタップ時 let alert: UIAlertController = UIAlertController(title: "tenji", message: data[indexPath.section][indexPath.row], preferredStyle: UIAlertControllerStyle.alert) let btnok: UIAlertAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: { (action: UIAlertAction!) -> Void in print("OK") }) alert.addAction(btnok) present(alert, animated: true, completion: nil) } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } }

iPhoneインラインアセンブラ入門、64bit Armマシン語はじめのいっぽ

2016/08/17
#Arm #swift 

IchigoJamもiPhoneも同じArmのCPU、IchigoJamでマシン語を覚えたらiPhoneでも使ってみましょう。今回の対象は、64bit化したArm64(Armv8)対応のiPhone5s以降です。ネットや書籍での資料には32bit時代のものも混在しているので注意が必要です。(iPhone Wikipedia)。

Swiftにはインラインアセンブラ機能はまだないようなので、Objective-CでGameをテンプレートに選び、次の行を viewDidLoad の [super viedDidLoad]; の後に追加します。

__asm__ volatile ("mov x0, x0");

※__asm__ はインラインアセンブラ、volatile で最適化を停止
エミュレーター向けだとコンパイルエラーになります。(IntelがArmライセンス取得とのことなので、MacBookへのArmv8組み込みにも期待!まずはApple-Aの生産から?詳しい解説記事


iPhoneでArm64マシン語、動きました!
(3Dの飛行機はサンプルのままで、今回のアセンブラでの動作とは無関係です)

mov x0, x0 は、レジスタX0の内容をレジスタX0に入れる(つまり、ほぼ何もしない)というマシン語を生成します。やっかいなことにこのコードはMacのiPhoneエミュレーターでは動きません。iPhoneエミュレーターはArmのCPUまでは動かしてくれないようです。実機向けにコンパイルすると動きます。(Arm64では64bitになったレジスタをRではなくXで呼ぶようになった様子)

Objective-Cでの変数との足し算をやってみます。

long num = 1; __asm__ volatile ( "mov x1, #1 \n\t" "add %[n], %[n], x1 \n\t" : [n] "+r" (num) : : "x1" ); NSLog(@"res: %ld\n", n);

コンソールに結果として 2 と表示されます。mov x1,#1 でレジスタX1に1を入れ、add命令で%[n]というコンパイラ任せなレジスタX?にX1の値を加えます。IchigoJamマシン語入門では X1=1 と表記していました。

最初のコロンの後 [n] "+r" (num) で、Objective-Cの変数numを%[n]というレジスタに割り当てて、読み書き"+"するよと指定しています。

三番目のコロンの後の "x1" で、インラインアセンブラ内で X1 レジスタを使用すると宣言して、前後のプログラムと干渉しないようにコンパイラに指定します。

これで基本はOKですね!
より詳しい解説は、こちら「Arm GCC Inline Assembler Cookbook」など参照ください

せっかくなので、アセンブラならでは機能を使った便利な関数を作ってみます。

- (unsigned long)rbit:(unsigned long)n { __asm__ volatile ( "rbit %[n], %[n] \n\t" : [n] "+r" (n) ); return n; }

rbitというのは、64のbit列を反転する命令です。普通に計算すると結構手間ですが、マシン語なら1クロック、0.1nsecで計算します!(参照、Arm64(Armv8) Assembly Programming (08) 分岐命令

iPhone(Armv8)とIchigoJam(Armv6-M)との比較です。

IchigoJamのCortex-M0のThumb-2命令とも互換性あるiPhone6sですが、浮動小数やSIMD命令など性能をフルに活かすならArm64マシン語プログラミングへのステップアップがオススメです!レジスタもたくさんあるので作るのも楽!

参考
- Arm64(Armv8) Assembly Programming (00)(とっても詳しいRAM64解説)
- 連載、IchigoJamではじめる、Armマシン語入門
- 連載、iPhoneゲームづくりからはじめる、Swift入門

スマホグラス、neo-plugがつないだメガネとスマホで目覚ましGlassをプロトタイピング

2016/05/30
#megane #swift #KidsIT 

メガネハッカソンでおもしろかった、スマホメガネ。
寝そうになったら震えるメガネのプロトタイプは、neo-plugと3Dプリンターでスマホをメガネにくっつけていました。


こちら動画へのインデックス
寝そうになったらメガネが震えます
加速度センサーとかついているしスマホをつけちゃえばいいじゃん(デモ直前)

実際試してみようと、傾いたら震えるアプリをiPhone用にSwiftでつくってみました。
MezamashiGlass - GitHub
CMMotionManagerを使った加速度センサーの値取得、AudioToolboxを使ったバイブのサンプルとしてどうぞ!
※背景色を変更しようとしていますが、なぜかうまくいってません!!

import UIKit import CoreMotion import AudioToolbox class ViewController: UIViewController { let motionManager = CMMotionManager() override func viewDidLoad() { super.viewDidLoad() // 加速度センサーON motionManager.accelerometerUpdateInterval = 0.3 // 0.3秒間隔で取得 motionManager.startAccelerometerUpdatesToQueue(NSOperationQueue()) { data, error in guard data != nil else { print("err: \(error)") return } print("x: \(data!.acceleration.x) y: \(data!.acceleration.y) z: \(data!.acceleration.z)") // 加速度に応じて背景色を変える if (abs(data!.acceleration.x) > 0.2) { self.view.backgroundColor = UIColor.redColor() AudioServicesPlayAlertSound(kSystemSoundID_Vibrate); } else { self.view.backgroundColor = UIColor.whiteColor() } } } override func shouldAutorotate() -> Bool { return false // 自動回転OFF } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } }

Swift、シンプルでいいですねっ!
2014年から急速に進んだ子供のパソコン離れ、こんなに楽しいツールに触れずに育つなんてもったいない!
小中高校生のパソコンや携帯電話利用率の実態(不破雷蔵) - 個人 - Yahoo!ニュース

「消コレ」以外の3チーム+αの発表動画、こちらです。

neo-plug+スマホのスマホメガネ、夢が広がりますね!
縦に接続すれば高画質カメラがついたメガネもシミュレート可能!
ちょっと軽めな iPhoneSE や、iPod touch が活躍しそう


今日のHana道場にはIntel、SAP、さくらインターネットからのお客様!(photo by Hana道場)


子供たちにも人気なネット接続デバイス、さくらIoT Platformの先行体験できちゃうかも!?

3Dプリンター、スマホアプリ、電子工作などで、わいわい遊ぶ子供たち。
創造する遊びは、最高の学びです!

iPhoneをIchigoJamのキーボードとして使う方法 - konashi(BLE)とSwiftとIchigoJam

2016/05/25
#konashi #IchigoJam #swift 

Bluetooth4.0を使ったお手軽フィジカルコンピューティングを実現するkonashiとの出会いが、電子工作再開のきっかけになりました! スーファミのコントローラーにつなげたり、いろいろやっている内に出会ったマイコンLPC1114、IchigoJam実現へとつながりました。


いよいよ今週末と迫ったメガネハッカソンに向けて、カドマックさん製、konashi互換のKoshianを使ったBLE小型ボードを入手したので早速接続!

以前SwiftでつくりかけていたKonashi接続用プログラムを現状Swiftに合わせてリメイク。konashiでは無事動作しました!(KoshianではなぜかUARTの通信速度設定が効かず難航中)

IchigoJamのコントロールやプログラムが、iPhoneからでもできちゃいます。BluetoothキーボードをiPhoneにつなげば普通にプログラミングもできそうですね!

特殊なキーは、ESCボタンだけつけていますが、どうぞいろいろと改造してみてください!
ソースコード(Swiftのプログラム)は、オープンソース、GitHub「IchigoRemote」に置きました!


新世代のメガネを創る!「メガネハッカソン
塚本教授に講評いただけます!(ウェアラブル新時代セミナー(HMDミーティング in 鯖江)連動)

ひなんメモ、避難所をローカルに保存するiOS9アプリ(Swift)

2016/04/15
#opendata #swift #SPARQL 

ひなんメモ(Webアプリ版)は、Webのオフラインアプリケーションの仕様頼みだったのに、 その機能はすでに廃止予定になっていて、iPhoneのSafariではもう動かなくなっていたので、Swift版つくってみました。(ソース on GitHub / Code for Fukui


現在位置をCLLocationManagerとiOS9で追加されたrequestLocationを使って位置情報を取得、その付近の避難所をodpからSAPRQLを使ってJSONで取得し、UITableViewを使ってリスト表示。 項目タップで地図が開きます。 取得したデータはCoreDataを使って端末内に保存しておき、クリアされない限り保持します。


ひさびさのSwift、以前書いた自分のブログ見てもアシスタントエディターを忘れていたので、図を追加。 実機で動作させようとしたら、バージョンが合わず、MacOSのアップデート、Xcodeのアップデート、設定、ライブラリ、Swiftの文法変更への対応など、なかなか手間取りました。 最近の開発環境は、がんがん更新されるので、初心者のプログラミング学習用途には向きません。
(伝統の++がSwift3では無くなる様子「【Swift3対応】Swift2.2以降のfor文法の書き方まとめ | ゆとりっち」)

実用化するにはまだ遠い「ひなんメモ」ですが、ぜひお好きなように改造しちゃってください!
ひなんメモ、ソース on GitHub / Code for Fukui

PREFIX geo: <http://www.w3.org/2003/01/geo/wgs84_pos#> PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> select ?s ?name ?lat ?lng { ?s rdf:type ; rdfs:label ?name; geo:lat ?lat; geo:long ?lng. filter(?lat<35.95 && ?lat>35.93 && ?lng<136.19 && ?lng>136.17) filter(lang(?name)="ja") }

(緯度経度の範囲を指定して避難所を日本語で取得するSARQLのクエリー)

Tweet
クリエイティブ・コモンズ・ライセンス
この作品は「Creative Commons — CC BY 4.0」の下に提供されています。
CC BY 福野泰介 - Taisuke Fukuno / @taisukef / アイコン画像 / プロフィール画像