1、 Raspberry 4B 開發板一塊
2、 可由5V驅動的Servo Motor 一顆 (DS3235SG 3Pin為GND、VDD、SIGNAL)
3、 鍵盤(接Raspberry 4B 開發板 USB port)
4、 可透過RPI4B連接網路的環境
4、 邏輯分析儀一臺(非必要,可用來確認輸出波行是否正確)
5、 WindowsPC一臺(非必要,可接邏輯分析儀監控輸出波型)
應用:攔截網的觸發
Learn More →
假設已擁有裝好ubuntu18.04與ROS(Melodic Morenia版)的RaspberryPi 4B開發板,並可透過RPI4B連上網路。無須準備其他軟體。
1、在ubuntu18.04中安裝PIGPIO。
2、在ROS中創建名為cap的專案(工作區)。
3、修改CMakeLists.txt檔案使ROS的C Compiler可連結PIGPIO函式庫。
4、使用catkin_make指令編譯.c檔,產生.exe檔案,下指令執行(sudo -./xxxx.exe)。
5、透過邏輯分析儀監控指定的GPIO輸出PULSE是否正確(非必要)。
P.S. PIGPIO函式庫中已有servo pwm pulse的相關範例與函式,可快速上手使用。
在ubuntu server 18.04命令列中透過以下指令下載與安裝PIGPIO
測試時是在 /home/user 位置執行下載、解壓縮並安裝
https://abyz.me.uk/rpi/pigpio/index.html PIGPIO官方網站。說明PIGPIO在RPI4B上的腳位編號(Pin Define) (RPI4B參考Type3)
rm master.zip
sudo rm -rf pigpio-mast
安裝Python相關工具
sudo apt install python-setuptools python3-setuptools
下載pigpio最新版本
wget https://github.com/joan2937/pigpio/archive/master.zip
解壓縮
unzip master.zip
進入解壓縮的資料夾
cd /home/user/pigpio-master
安裝pigpio
make
sudo make install
關閉所有正在執行中的pigpio node(注意指令中pigpiod結尾的"d"不要忘記打)
沒先執行這行會報錯 pigpio Can't lock /var/run/pigpio.pid
sudo killall pigpiod
check C I/F
sudo ./x_pigpio
start daemon
sudo pigpiod
check C I/F to daemon
./x_pigpiod_if2*
check Python I/F to daemon
./x_pigpio.py
check pigs I/F to daemon
./x_pigs
check pipe I/F to daemon
./x_pipe
================================================================
安裝PIGPIO之參考網頁
https://abyz.me.uk/rpi/pigpio/index.html PIGPIO官方網站。PIGPIO在不同硬體上的腳位編號(Pin Define)
https://abyz.me.uk/rpi/pigpio/ PIGPIO官方網站 (卡巴斯基會觸發警告)
https://abyz.me.uk/rpi/pigpio/ PIGPIO官方網站 下載與安裝
https://blog.csdn.net/weixin_41756645/article/details/125417549
================================================================
在/home/user路徑下創建名為"cap"的工作資料夾
cd /home/user
mkdir cap
進入剛才創建的cap資料夾
cd /home/user/cap
在工作區中創建一個src資料夾用來放置package資料夾與程式檔案
mkdir src
進入剛才創建的src資料夾,創建一個名為catch_net的Package
cd /home/user/cap/src
catkin_create_pkg catch_net std_msgs rospy roscpp
在Package的資料夾中再創建一個src資料夾用來放置要執行的Node(程式檔案)
mkdir src
cd /home/user/cap/src/catch_net/src
創建名為servo_trig.c的Node並將要執行的動作寫進.c檔案
sudo vim servo_trig.c
================================================================
https://ithelp.ithome.com.tw/articles/10202723
https://ithelp.ithome.com.tw/articles/10203126
================================================================
返回上一層,開啟CMakeLists.txt檔準備修改
cd /home/user/cap/src/catch_net
sudo vim CMakeLists.txt
//...上略
## Declare a C++ executable
## ...
## ...
## ...
add_executable(servo_trig.exe src/servo_trig.c)
target_link_libraries(servo_trig.exe ${catkin_LIBRARIES} -lpigpio -lrt)
## Rename C++ executable without prefix
//...下略
-lpigpio:pigpio library。連結pigpio函式庫。
-lrt:Realtime Extensions library。
回到cap專案資料夾(工作區)並使用編譯器將.c檔編譯成.exe
cd /home/user/cap
catkin_make
進入檔資料夾執行編譯後產生的.exe檔
cd /home/user/cap/devel/lib/catch_net
sudo ./servo_trig.exe
P.S.
第二行
sudo ./servo_trig.exe
後面可以接數字,
代表要求輸出PWM的GPIO腳位編號,
若不輸入任何數字則默認用GPIO 4腳位(pin7)輸出。
一般來說要依據Servo控制pin所接的位置來決定要用哪個腳位輸出。
例如輸入
sudo ./servo_trig.exe 4 22
代表要求GPIO 4(pin7)與GPIO 22(pin15)兩個腳位同時輸出PWM訊號。
Raspberry 4b GPIO Pinout可以在官方網站查詢
https://pinout.xyz/
================================================================
================================================================
================================================================
範例:使用邏輯分析儀檢查以下資訊
pigpio第4pin輸出的pwm訊號是否為50Hz,波寬1100us(1.1ms)/1900us(1.9ms)?
================================================================
P.S.1
以下測試用程式碼以50Hz控制頻率(PWM週期20ms),每隔400ms切換1100us/1900us pwm pulse width驅動servo轉動。
P.S.2
以下內容是從官方Servo Pulse Generator範例文件Servo_demo.c修改而來。
#ifdef __cplusplus
extern "C"
{
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <pigpio.h>
#include <time.h>
}
#endif
#include <ros/ros.h>
#include <termios.h>
#include <sys/select.h>
#include <stropts.h>
#include <unistd.h>
#include <sys/ioctl.h>
#define NUM_GPIO 32
#define MIN_WIDTH 500
#define MAX_WIDTH 2500
#define TRIG_GPIO_NUM 4
int run=1;
int step[NUM_GPIO];
int width[NUM_GPIO];
int used[NUM_GPIO];
//===========
#define TRIG_PERIOD 400000000 //nsec
#define MID_WIDTH 1500 //usec
#define OFFSET_WIDTH 400 //usec
#define TRIG_DURATION 350000000 //nsec
#define TRIG_WIDTH 1050 //usec
#define UNTRIG_WIDTH 1420 //usec
#define CMD_LEN 1
struct timespec trig_prev, t_now;
//===========
static int peek_character = -1;
int readch(void);
int _kbhit(void);
int randint(int from, int to)
{
return (random() % (to - from + 1)) + from;
}
void stop(int signum)
{
run = 0;
}
int readch()
{
char ch;
if(peek_character != -1)
{
ch = peek_character;
peek_character = -1;
return ch;
}
read(0,&ch,1);
return ch;
}
int _kbhit()
{
static const int STDIN = 0;
static bool initialized = false;
if (!initialized)
{
termios term;
tcgetattr(STDIN, &term);
term.c_lflag &= ~ICANON;
tcsetattr(STDIN,TCSANOW, &term);
setbuf(stdin, NULL);
initialized = true;
}
int bytesWaiting;
ioctl(STDIN, FIONREAD, &bytesWaiting);
return bytesWaiting;
}
int main(int argc, char *argv[])
{
int i, g;
if(gpioInitialise() < 0) return -1;
gpioSetSignalFunc(SIGINT, stop);
if(argc==1) used[TRIG_GPIO_NUM]=1;
else
{
for(i=1;i<argc;i++)
{
g = atoi(argv[i]);
if((g>=0) && (g<NUM_GPIO)) used[g] = 1;
}
}
for(g=0; g<NUM_GPIO; g++)
{
if(used[g])
{
width[g]=UNTRIG_WIDTH;
gpioServo(g, width[g]);
printf("[%d %d]\n", g, width[g]);
}
}
printf("Sending servos pulses to GPIO");
printf(", control C to stop.\n");
while(run)
{
int bytes_rcv = _kbhit();
if(bytes_rcv)
{
int c[CMD_LEN];
for(int i=0;i<CMD_LEN;i++)
{
c[i] = readch();
}
printf("\nlen:%d key:%d\n",bytes_rcv,c[0]);
if(c[0]=='#')
{
printf("\nlen:%d key:%d Trigger.\n",bytes_rcv,c[0]);
for(g=0; g<NUM_GPIO; g++)
{
if(used[g])
{
width[g]=TRIG_WIDTH;
gpioServo(g, width[g]);
printf("[%d %d]\n", g, width[g]);
}
}
time_sleep((float)TRIG_DURATION/(float)1000000000);
for(g=0; g<NUM_GPIO; g++)
{
if(used[g])
{
width[g]=UNTRIG_WIDTH;
gpioServo(g, width[g]);
printf("[%d %d]\n", g, width[g]);
}
}
time_sleep((float)TRIG_DURATION/(float)1000000000);
}
}
}
printf("\ntidying up\n");
for(g=0; g<NUM_GPIO; g++)
{
if(used[g]) gpioServo(g, 0);
}
gpioTerminate();
return 0;
}
P.S.3
以下內容是Shaw(紹瑋)最後實際寫進ROS的Pytron程式碼,用來控制Servo轉動固定角度,觸發攔截網發射。
import pigpio
import time
import rospy
from std_msgs.msg import Int32
servo_pin = 4 # GPIO pin number where the servo signal wire is connected
pi = pigpio.pi()
# Function to set the servo angle
fire = 0
def fire_cb(msg):
global fire
fire = msg.data
if fire == 1:
rospy.loginfo("Fire!")
pi.set_servo_pulsewidth(servo_pin, 1050)
time.sleep(2)
pi.set_servo_pulsewidth(servo_pin, 1420)
if __name__ == '__main__':
rospy.init_node('gps_init_py')
fire_sub = rospy.Subscriber('/fire', Int32, fire_cb)
# Create a PWM object with a frequency of 50Hz
pi.set_servo_pulsewidth(servo_pin, 1420)
rospy.spin()