@@ -10,6 +10,8 @@ import (
1010 "os"
1111 "os/exec"
1212 "os/signal"
13+ "strconv"
14+ "strings"
1315 "time"
1416
1517 "github.com/Rione-SSL/RACOON-Pi/proto/pb_gen"
@@ -35,7 +37,7 @@ const BALLSENS_LOW_THRESHOULD int = 100
3537
3638// バッテリーの低下しきい値。 150 = 15.0V
3739const BATTERY_LOW_THRESHOULD int = 150
38- const BATTERY_CRITICAL_THRESHOULD int = 140
40+ const BATTERY_CRITICAL_THRESHOULD int = 145
3941
4042var sendarray bytes.Buffer //送信用バッファ
4143
@@ -71,7 +73,7 @@ var imuError bool = false
7173var last_recv_time time.Time = time .Now ()
7274
7375// ポート8080番で待ち受ける。
74- const PORT string = ":8080 "
76+ const PORT string = ":9191 "
7577
7678func RunApi (chapi chan bool , MyID uint32 ) {
7779 //ポートを開く
@@ -87,6 +89,8 @@ func RunApi(chapi chan bool, MyID uint32) {
8789 if err != nil {
8890 log .Fatal (err )
8991 }
92+ // log
93+ log .Println ("Remote API Connected by " , conn .RemoteAddr ())
9094 //接続があったら処理を行う
9195 go HandleRequest (conn )
9296 }
@@ -100,27 +104,119 @@ var RobotErrorMessage = ""
100104
101105var ballSensLowCount = 0
102106
107+ var doBuzzer = false
108+ var buzzerTone = 0
109+ var buzzerTime time.Duration = 0 * time .Millisecond
110+
111+ var alarmIgnore = false
112+
103113// 接続があったら処理を行う
104114func HandleRequest (conn net.Conn ) {
105- //200 OKを返す
106- fmt .Fprintf (conn , "HTTP/1.1 200 OK\r \n " )
107-
108- //そのまま、recvdataをJson形式で返す
109- //fmt.Fprintf(conn, "%s", recvdata)
110-
111- //Json形式で返す
112- fmt .Fprintf (conn , "{" )
113- fmt .Fprintf (conn , "\" VOLT\" : %f," , float32 (recvdata .Volt )/ 10.0 )
114- fmt .Fprintf (conn , "\" PHOTOSENSOR\" :%d," , recvdata .PhotoSensor )
115- fmt .Fprintf (conn , "\" ISHOLDBALL\" :%t," , recvdata .IsHoldBall )
116- fmt .Fprintf (conn , "\" IMUDIR\" :%d" , recvdata .ImuDir )
117- fmt .Fprintf (conn , "\" ERROR \" :%t" , isRobotError )
118- fmt .Fprintf (conn , "\" ERRORCODE \" :%d" , RobotErrorCode )
119- fmt .Fprintf (conn , "\" ERRORMESSAGE \" :%s" , RobotErrorMessage )
120- fmt .Fprintf (conn , "}" )
121-
122- //接続を閉じる
123- conn .Close ()
115+ defer conn .Close ()
116+
117+ //リクエストを解析
118+ buf := make ([]byte , 1024 )
119+ _ , err := conn .Read (buf )
120+ if err != nil {
121+ log .Println (err )
122+ return
123+ }
124+
125+ // リクエストを解析
126+ // リクエストヘッダーの1行目を取得
127+ request := string (buf )
128+ // リクエストヘッダーの1行目をスペースで区切る
129+ requests := strings .Split (request , " " )
130+ // リクエストヘッダーの1行目からリクエストの種類を取得
131+ requestType := requests [0 ]
132+
133+ // リクエストの種類がGETでなければエラーを返す
134+ if requestType != "GET" {
135+ fmt .Fprintf (conn , "HTTP/1.1 400 Bad Request\r \n " )
136+ fmt .Fprintf (conn , "Content-Type: text/plain; charset=utf-8\r \n \r \n " )
137+ fmt .Fprintf (conn , "400 Bad Request\r \n " )
138+ return
139+ }
140+
141+ // リクエストのパスが"/buzzer"の場合
142+ if strings .Split (requests [1 ], "/" )[1 ] == "buzzer" {
143+ // tone が指定されていない場合
144+ if len (requests ) < 3 {
145+ fmt .Fprintf (conn , "HTTP/1.1 400 Bad Request\r \n " )
146+ fmt .Fprintf (conn , "Content-Type: text/plain; charset=utf-8\r \n \r \n " )
147+ fmt .Fprintf (conn , "400 Bad Request\r \n " )
148+ return
149+ }
150+ // buzzer/ の後に tone が指定されている場合
151+ log .Println (strings .Split (requests [1 ], "/" )[1 ])
152+ tone , err := strconv .Atoi (strings .Split (requests [1 ], "/" )[3 ])
153+ if err != nil {
154+ fmt .Fprintf (conn , "HTTP/1.1 400 Bad Request\r \n " )
155+ fmt .Fprintf (conn , "Content-Type: text/plain; charset=utf-8\r \n \r \n " )
156+ fmt .Fprintf (conn , "400 Bad Request\r \n " )
157+ return
158+ }
159+ duration , err := strconv .Atoi (strings .Split (requests [1 ], "/" )[4 ])
160+ if err != nil {
161+ fmt .Fprintf (conn , "HTTP/1.1 400 Bad Request\r \n " )
162+ fmt .Fprintf (conn , "Content-Type: text/plain; charset=utf-8\r \n \r \n " )
163+ fmt .Fprintf (conn , "400 Bad Request\r \n " )
164+ return
165+ }
166+ // tone が 0 から 12 でない場合
167+ if tone < 0 || tone > 15 {
168+ fmt .Fprintf (conn , "HTTP/1.1 400 Bad Request\r \n " )
169+ fmt .Fprintf (conn , "Content-Type: text/plain; charset=utf-8\r \n \r \n " )
170+ fmt .Fprintf (conn , "400 Bad Request\r \n " )
171+ return
172+ }
173+ // duration が 50 から 3000 でない場合
174+ if duration < 50 || duration > 3000 {
175+ fmt .Fprintf (conn , "HTTP/1.1 400 Bad Request\r \n " )
176+ fmt .Fprintf (conn , "Content-Type: text/plain; charset=utf-8\r \n \r \n " )
177+ fmt .Fprintf (conn , "400 Bad Request\r \n " )
178+ return
179+ }
180+
181+ // OK と表示
182+ fmt .Fprintf (conn , "HTTP/1.1 200 OK\r \n " )
183+ fmt .Fprintf (conn , "Content-Type: text/plain; charset=utf-8\r \n \r \n " )
184+ fmt .Fprintf (conn , "BUZZER OK\r \n " )
185+ //ブザーを1秒鳴らす
186+ doBuzzer = true
187+ buzzerTone = tone
188+ buzzerTime = time .Duration (duration ) * time .Millisecond
189+ return
190+ }
191+
192+ if strings .Split (requests [1 ], "/" )[1 ] == "ignorebatterylow" {
193+ // OK と表示
194+ fmt .Fprintf (conn , "HTTP/1.1 200 OK\r \n " )
195+ fmt .Fprintf (conn , "Content-Type: text/plain; charset=utf-8\r \n \r \n " )
196+ fmt .Fprintf (conn , "IGNORE BATTERY LOW OK\r \n " )
197+ //アラーム無視をセットする
198+ alarmIgnore = true
199+ return
200+ }
201+
202+ // 200 OKを返す
203+ fmt .Fprintf (conn , "HTTP/1.1 200 OK\r \n " )
204+ // UTF-8指定
205+ fmt .Fprintf (conn , "Content-Type: application/json; charset=utf-8\r \n \r \n " )
206+
207+ // JSON形式で返す
208+ response := fmt .Sprintf (`{
209+ "VOLT": %f,
210+ "PHOTOSENSOR": %d,
211+ "ISHOLDBALL": %t,
212+ "IMUDIR": %d,
213+ "ERROR": %t,
214+ "ERRORCODE": %d,
215+ "ERRORMESSAGE": "%s"
216+ }` , float32 (recvdata .Volt )/ 10.0 , recvdata .PhotoSensor , recvdata .IsHoldBall , recvdata .ImuDir , isRobotError , RobotErrorCode , RobotErrorMessage )
217+
218+ fmt .Fprint (conn , response )
219+
124220}
125221
126222// シリアル通信部分
@@ -196,12 +292,12 @@ func RunSerial(chclient chan bool, MyID uint32) {
196292 RobotErrorMessage = "ボールセンサ異常"
197293 }
198294
199- //ボールセンサの値が極端に高いときはエラー
200- if recvdata .PhotoSensor > uint16 (BALLSENS_HBREAK_THRESHOULD ) {
201- isRobotError = true
202- RobotErrorCode = 1
203- RobotErrorMessage = "ボールセンサ異常(回路故障の可能性)"
204- }
295+ // // ボールセンサの値が極端に高いときはエラー
296+ // if recvdata.PhotoSensor > uint16(BALLSENS_HBREAK_THRESHOULD) {
297+ // isRobotError = true
298+ // RobotErrorCode = 1
299+ // RobotErrorMessage = "ボールセンサ異常(回路故障の可能性)"
300+ // }
205301
206302 //ボールセンサの値が極端に低いときはエラー
207303 if recvdata .PhotoSensor < uint16 (BALLSENS_LBREAK_THRESHOULD ) {
@@ -226,6 +322,10 @@ func RunSerial(chclient chan bool, MyID uint32) {
226322 isRobotEmgError = true //緊急停止
227323 }
228324
325+ //TODO: Pendingをfalseにした瞬間にAIが受信し始める。Mutex必要か?
326+ if imuResetPending {
327+ imuResetPending = false
328+ }
229329 //クライアントで受け取ったデータをバイト列に変更
230330 sendbytes := sendarray .Bytes ()
231331
@@ -236,7 +336,7 @@ func RunSerial(chclient chan bool, MyID uint32) {
236336
237337 //受信しなかった場合に自動的にモーターOFFする
238338 if time .Since (last_recv_time ) > 1 * time .Second {
239- log .Println ("No Data Recv" )
339+ // log.Println("No Data Recv")
240340 for i := 2 ; i <= 4 ; i ++ {
241341 sendbytes [i ] = 100
242342 }
@@ -249,7 +349,7 @@ func RunSerial(chclient chan bool, MyID uint32) {
249349 }
250350
251351 //それぞれのデータを表示
252- log .Printf ("VOLT: %f, BALLSENS: %t, IMUDEG: %d\n " , float32 (recvdata .Volt )* 0.1 , recvdata .IsHoldBall , recvdata .ImuDir )
352+ // log.Printf("VOLT: %f, BALLSENS: %t, IMUDEG: %d\n", float32(recvdata.Volt)*0.1, recvdata.IsHoldBall, recvdata.ImuDir)
253353
254354 //高速回転防止機能
255355 //フレームごとの角度が閾値を超えると, EMGをセットする
@@ -283,7 +383,7 @@ func RunSerial(chclient chan bool, MyID uint32) {
283383 port .Write (sendbytes ) //書き込み
284384 time .Sleep (16 * time .Millisecond ) //少し待つ
285385 //log.Printf("Sent %v bytes\n", n) //何バイト送信した?
286- log .Println (sendbytes ) //送信済みのバイトを表示
386+ // log.Println(sendbytes) //送信済みのバイトを表示
287387
288388 //100ナノ秒待つ
289389 time .Sleep (100 * time .Nanosecond )
@@ -376,22 +476,33 @@ func RunGPIO(chgpio chan bool) {
376476
377477 //Lチカ速度
378478 ledsec := 500 * time .Millisecond
479+ alarmVoltage := BATTERY_LOW_THRESHOULD
379480 for {
380481 //電圧降下検知
381- if recvdata .Volt <= 155 {
382- buzzer .Freq (1200 * 64 )
383- buzzer .DutyCycle (16 , 32 )
482+ if recvdata .Volt <= uint8 (alarmVoltage ) {
483+ for {
484+ buzzer .Freq (1200 * 64 )
485+ buzzer .DutyCycle (16 , 32 )
486+
487+ //高速チカチカ
488+ led2 .High ()
489+ time .Sleep (100 * time .Millisecond )
384490
385- //高速チカチカ
386- led2 .High ()
387- time .Sleep (100 * time .Millisecond )
491+ buzzer . Freq ( 760 * 64 )
492+ led2 .Low ()
493+ time .Sleep (150 * time .Millisecond )
388494
389- buzzer .Freq (760 * 64 )
390- led2 .Low ()
391- time .Sleep (150 * time .Millisecond )
495+ if button1 .Read ()^ 1 == rpio .High || alarmIgnore == true {
496+ //一時的にアラーム解除する
497+ log .Println ("BATTERY ALARM IGNORED" )
498+ alarmVoltage = BATTERY_CRITICAL_THRESHOULD
499+ break
500+ }
501+ }
392502 } else {
393503 //通常チカチカ。ボタンが押されたら高速チカチカ
394504 //ボタンが押されたら、imuをリセットする
505+ buzzer .Freq (1479 * 64 )
395506 time .Sleep (ledsec )
396507 led .Write (rpio .High )
397508 if button1 .Read ()^ 1 == rpio .High {
@@ -413,6 +524,14 @@ func RunGPIO(chgpio chan bool) {
413524 time .Sleep (ledsec )
414525 led .Write (rpio .Low )
415526 buzzer .DutyCycle (0 , 32 )
527+
528+ if doBuzzer {
529+ buzzer .Freq (int (440 * math .Pow (1.0595 , float64 (buzzerTone ))) * 64 )
530+ buzzer .DutyCycle (16 , 32 )
531+ time .Sleep (buzzerTime )
532+ buzzer .DutyCycle (0 , 32 )
533+ doBuzzer = false
534+ }
416535 }
417536 }
418537}
@@ -596,7 +715,7 @@ func RunServer(chserver chan bool, MyID uint32) {
596715 defer conn .Close ()
597716
598717 for {
599- log .Println (recvdata .IsHoldBall )
718+ // log.Println(recvdata.IsHoldBall)
600719 pe := createStatus (int32 (MyID ), recvdata .IsHoldBall , false , false )
601720 Data , _ := proto .Marshal (pe )
602721
@@ -607,6 +726,10 @@ func RunServer(chserver chan bool, MyID uint32) {
607726
608727}
609728
729+ // IMU Resetを確実に行うためのフラグ
730+ // 待機モードにうつり、これがセットされているときはAIから受け取らない
731+ var imuResetPending bool = false
732+
610733// AIからの情報を受信するクライアント
611734func RunClient (chclient chan bool , MyID uint32 , ip string ) {
612735
@@ -750,10 +873,11 @@ func RunClient(chclient chan bool, MyID uint32, ip string) {
750873 //log.Printf("Velnormalized: %f", Velnormalized)
751874 //log.Printf("Float64BeforeInt: %f", Motor)
752875 sendarray = bytes.Buffer {}
753- err := binary .Write (& sendarray , binary .LittleEndian , bytearray ) //バイナリに変換
754-
755- if err != nil {
756- log .Fatal (err )
876+ if imuResetPending == false {
877+ err := binary .Write (& sendarray , binary .LittleEndian , bytearray ) //バイナリに変換
878+ if err != nil {
879+ log .Fatal (err )
880+ }
757881 }
758882 }
759883 //IDが255のときは、モーター動作させず緊急停止フェーズに移行
@@ -827,6 +951,9 @@ func RunClient(chclient chan bool, MyID uint32, ip string) {
827951
828952 log .Println ("=======IMU RESET(RESET TO ANGLE)=======" )
829953
954+ //IMU Reset Pending フラグをたてる
955+ imuResetPending = true
956+
830957 if err != nil {
831958 log .Fatal (err )
832959 }
0 commit comments