[ロボスイープ]RaspberryPiからSTM32マイコンを制御する!

ロボスイープ

こんにちは!東京理科大学Miceです。今回はロボスイープ競技に向けた実験ということで、RaspberryPi ZeroからSTM32のマイコンを操作してみました!

概要

  • RaspberryPi ZeroとSTM32F446間でUART通信(前回記事)の続き
  • 専用のコマンドを作成
  • コマンドごとに動作をするようプログラムを組んだ!

前回の記事

使用器具

  • PC(Windows11)
  • 各種ソフト(STM Cube IDE, Teraterm等)
  • STM32 Nucleo-F446RE(Nucleo)
  • Raspberry Pi Zero 2 W)(Raspberry Pi OS,ラズベリーパイ Zero)
  • ブレッドボード,ジャンプワイヤ

実験系

ブレッドボード経由でラズベリーパイ ZeroとNucleoを接続しています。また、Nucleoには追加でLEDを3つ接続しています。

コマンドの構造

コマンドは、「オペレーター」と「オペランド」の組み合わせで実装されます。オペレーターはコマンドの種類を決めるもので、3文字です。例)LED, MTR, MAP

オペランドは残りの部分です。LEDならどのLEDかや光らせ方を記述します。

例)LED1H … LED1番をHIGHにする

コマンドの最後は改行(\n)で締めます。

今後しばらくはこのフォーマットで開発していきます!

ラズベリーパイ Zeroからコマンドを送信する

import serial
import time

serial = serial.Serial('/dev/serial0', 115200, timeout=3)

while True:
    msg = "LED1H\r\n"
    serial.write(msg.encode())
    time.sleep(0.5)

    msg = "LED2H\r\n"
    serial.write(msg.encode())
    time.sleep(0.5)

    msg = "LED3H\r\n"
    serial.write(msg.encode())
    time.sleep(0.5)

    print("LED ON")
    time.sleep(1)
    
    msg = "LED1L\n\r"
    serial.write(msg.encode())
    time.sleep(0.5)
    
    msg = "LED2L\r\n"
    serial.write(msg.encode())
    time.sleep(0.5)
    
    msg = "LED3L\r\n"
    serial.write(msg.encode())
    time.sleep(0.5)

    print("LED OFF")
    time.sleep(1)

定期的にコマンドを送るだけです。

Nucleoで受信コマンドを処理する

USART受信割り込みで処理する

NucleoにはUSART信号を受信した際に割り込む設定ができるので、そこで使用するハンドラーを以下のように作成しました。ハンドラーはstm32f4xx_it.cで適用します。

// AL_communicateRaspberryPi.c

void RaspberryPi_UART_Handler()
{
    // 改行が来たらメッセージを処理
    if (rx_data == '\n')
        {
            SEGGER_RTT_Write(0, rx_buffer, rx_index + 1);

            CommandProcessor((chat*) rx_buffer, rx_index + 1));
            rx_index = 0;
        }
        else
        {
            // バッファに格納
      rx_buffer[rx_index] = rx_data;
            rx_index += 1;
        }

         // 次の1文字を受信開始
     HAL_UART_Receive_IT(&huart1, &rx_data, 1);
         SEGGER_RTT_Write(0, &rx_data, 1);
}

改行が来たら処理が走るようにしています。SEGGER_RTT_Write関数は便利なprintfみたいなものです。MiceではST-LINKをJ-LINK化して使っていることもあり、せっかくなので使ってみました。特に意味はないです。

// stm32f4xx_it.c
void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */

  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */
  RaspberryPi_UART_Handler();

  /* USER CODE END USART1_IRQn 1 */
}

受信したコマンドは以下のプログラムで分類します。

void CommandProcessor(char *command, int len) {
	// オペレータ(コマンド識別子) 3文字
	uint32_t operator_code = (command[0] << 16) | (command[1] << 8)
			| command[2];

	switch (operator_code) {
	case ('L' << 16) | ('E' << 8) | 'D':
		Command_LED_Handler(command, len);
		break;
	}
}

‘L’ << 16) | (‘E’ << 8) | ‘D’の部分は後々管理が面倒になりそうなので、今後別の書き方を考えるか、関数化したいと思っています。LEDコマンド個別の処理は以下のようにしています。

void Command_LED_Handler(char *command, int len) {
	int out_state = 0;

	if (command[4] == 'H') {
		out_state = GPIO_PIN_SET;
	} else if (command[4] == 'L') {
		out_state = GPIO_PIN_RESET;
	}

	switch (command[3])
	{
	case '1':
                HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, out_state);
	        break;
	case '2':
		HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, out_state);
		break;
	case '3':
		HAL_GPIO_WritePin(LED3_GPIO_Port, LED3_Pin, out_state);
		break;
	}
}

コマンドを見て、どのLEDか、HIGH・LOWのどちらに設定するかを決めているだけです。

実行結果

編集中!

3つのLEDが順番に点灯し、その後順番に消灯することが確認できると思います。大成功ですね!

次の予定

とりあえず操作に成功しました!次回はモーターの制御をやりたいと思っています。また、今のままだと整備性が悪いので、関数や列挙子などを活用できないか模索する予定です!

コメント

タイトルとURLをコピーしました