目录
零.前言
1.jetson nano购买商家及技术支持
2.相关环境配置
3.做好系统备份
一.vscode远程ssh操作(局域网连接)
二.板载摄像头教程:
三.运行例程
四.GPIO使用
GPIO库的API用法
1.导入库
2.引脚编号
3.警告
4.设置通道
5.输入
6.输出
set first channel to HIGH and rest to LOW
7.清理
8.jetson模块信息和库版本
9.中断
wait_for_edge()函数
timeout is in milliseconds
event_detected()函数
set rising edge detection on the channel
当检测到边缘时运行回调函数
define callback function
add rising edge detection
bouncetime set in milliseconds
10.检查GPIO通道的功能
11. PWM
五.串口通信
<1>UART
1.python代码:JetsonHacksNano/UARTDemo: UART Demo Code (github.com)
注意事项:如果使用USB转TTL模块电脑和nano进行通信注意一下几点
2.C++代码:Uart c++ class for Nvidia Jetson Nano
六.在jetson nano上使用OpenCV
七.jetson nano开机自启动程序
八.实战程序
1.jetson nano上进行霍夫圆检测并将圆心坐标通过uart传给stm32
***选购亚博,支持相关开源资料,资料网址:JETSON NANO B01 (yahboom.com)
***常见问题及解答:Jetson nano A01/B01 (yuque.com)
<1>亚博已经在SD卡中将环境配好,插上即可直接使用
<2>***自行烧录镜像,配置环境:
下载之前要格式化SD卡或者U盘,具体操作见“jetson—主板—2.Jetson Nano B01基础教程”,然后烧录镜像文件:
亚博资料里的 “jetson—主板—附录—镜像” 包含已安装:
CUDA10.2、CUDNNv8、tensorRT、opencv4.1.1、python2、python3、tensorflow2.3、jetpack4.6.1、yolov5、jetson-inference包(包括相关模型)、jetson-gpio库、安装pytorch1.8和torchvesion0.9、安装node v15.0.1、npm7.2.3,jupyter,已开启VNC服务,还有其他课程中所用到的模块。
以及Swap空间配置,Jtop安装,只需要TF/U盘扩容即可
减少自行配置的麻烦。
如果要从零开始自己配置,“jetson—主板—2.Jetson Nano B01基础教程” 和“4.系统基础设置教程”中包括了大部分操作,甚至包括空环境下载
如果只是使用亚博官方提供的版本库,可以只用 “jetson—主板—附录—镜像” 中的镜像文件作为备份。如果自行配置了其他环境,建议备份系统,可在“jetson—主板—4.系统基础设置教程” 找到具体操作。
1.将jetson连接至路由器——电脑使用该路由wifi——打开VS Code——下载ssh-remote插件——jetson上终端ifconfig查ip——vscode按格式输入:ssh jetson@IP地址——输入密码登录(原始默认用户名为jetson,密码为yahboom)
2.crtl+o选择要打开的文件或侧栏资源管理器选择,文件可在主机写好直接拖入jetson;终端写入代码并操作
获取摄像头相关参数:linux查看摄像头分辨率参数
Driver Info (not using libv4l2):
Driver name : tegra-video
Card type : vi-output, imx219 8-0010
Bus info : platform:54080000.vi:4
Driver version: 4.9.255
Capabilities : 0x84200001
Video Capture
Streaming
Extended Pix Format
Device Capabilities
Device Caps : 0x04200001
Video Capture
Streaming
Extended Pix Format
Priority: 2
Video input : 0 (Camera 4: ok)
Format Video Capture:
Width/Height : 3264/2464
Pixel Format : 'RG10'
Field : None
Bytes per Line : 6528
Size Image : 16084992
Colorspace : sRGB
Transfer Function : Default (maps to sRGB)
YCbCr/HSV Encoding: Default (maps to ITU-R 601)
Quantization : Default (maps to Full Range)
Flags :
Camera Controls
group_hold 0x009a2003 (bool) : default=0 value=0 flags=execute-on-write
sensor_mode 0x009a2008 (int64) : min=0 max=0 step=0 default=0 value=0 flags=slider
gain 0x009a2009 (int64) : min=0 max=0 step=0 default=0 value=16 flags=slider
exposure 0x009a200a (int64) : min=0 max=0 step=0 default=0 value=13 flags=slider
frame_rate 0x009a200b (int64) : min=0 max=0 step=0 default=0 value=2000000 flags=slider
bypass_mode 0x009a2064 (intmenu): min=0 max=1 default=0 value=0
override_enable 0x009a2065 (intmenu): min=0 max=1 default=0 value=0
height_align 0x009a2066 (int) : min=1 max=16 step=1 default=1 value=1
size_align 0x009a2067 (intmenu): min=0 max=2 default=0 value=0
write_isp_format 0x009a2068 (bool) : default=0 value=0
sensor_signal_properties 0x009a2069 (u32) : min=0 max=0 step=0 default=0 flags=read-only, has-payload
sensor_image_properties 0x009a206a (u32) : min=0 max=0 step=0 default=0 flags=read-only, has-payload
sensor_control_properties 0x009a206b (u32) : min=0 max=0 step=0 default=0 flags=read-only, has-payload
sensor_dv_timings 0x009a206c (u32) : min=0 max=0 step=0 default=0 flags=read-only, has-payload
low_latency_mode 0x009a206d (bool) : default=0 value=0
preferred_stride 0x009a206e (int) : min=0 max=65535 step=1 default=0 value=0
sensor_modes 0x009a2082 (int) : min=0 max=30 step=1 default=30 value=6 flags=read-only
注意jetson nano要连接显示屏
jetson@yahboom:/home$ nvgstcapture-1.0 //打开摄像头命令
响应:
Encoder null, cannot set bitrate!
Encoder Profile = High
Supported resolutions in case of ARGUS Camera //设置分辨率
(2) : 640x480
(3) : 1280x720
(4) : 1920x1080
(5) : 2104x1560
(6) : 2592x1944
(7) : 2616x1472
(8) : 3840x2160
(9) : 3896x2192
(10): 4208x3120
(11): 5632x3168
(12): 5632x4224
Runtime ARGUS Camera Commands:
Help : 'h'
Quit : 'q'
Set Capture Mode:
mo:
(1): image
(2): video
Get Capture Mode:
gmo
Set sensor orientation:
so:
(0): none
(1): Rotate counter-clockwise 90 degrees
(2): Rotate 180 degrees
(3): Rotate clockwise 90 degrees
Get sensor orientation:
gso
Set sensor mode:
smo:
Get sensor mode:
gsmo
Set Whitebalance Mode: //更改相机参数(曝光、饱和度等等)
wb:
(0): off
(1): auto
(2): incandescent
(3): fluorescent
(4): warm-fluorescent
(5): daylight
(6): cloudy-daylight
(7): twilight
(8): shade
(9): manual
Get Whitebalance Mode:
gwb
Set Saturation (0 to 2):
st:
Get Saturation:
gst
Set Exposure Compensation (-2 to 2):
ec:
Get Exposure Compensation:
gec
Set Auto Whitebalance Lock:
awbl:
Get Auto Whitebalance Lock:
awbl
Set Auto Exposure Lock:
ael:
Get Auto Exposure Lock:
gael
Set TNR Mode:
tnrm:
(0): OFF
(1): FAST
(2): HIGH QUALITY
Get TNR Mode:
gtnrm
Set TNR Strength (-1 to 1):
tnrs:
Get TNR Strength:
gtnrs
Set EE Mode:
eem:
(0): OFF
(1): FAST
(2): HIGH QUALITY
Get EE Mode:
geem
Set EE Strength (-1 to 1):
ees:
Get EE Strength:
gees
Set Auto Exposure Anti-Banding (0 to 3):
aeab:
(0): OFF
(1): MODE AUTO
(2): MODE 50HZ
(3): MODE 60HZ
Get Auto Exposure Anti-Banding:
gaeab
Set Gain Range:
gr:
Get Gain Range:
ggr
Set Exposure Time Range:
etr:
Get Exposure Time Range:
getr
Set ISP Digital Gain Range:
dgr:
Get ISP Digital Gain Range:
gdgr
Capture: enter 'j' OR
followed by a timer (e.g., jx5000, capture after 5 seconds) OR
followed by multishot count (e.g., j:6, capture 6 images)
timer/multihot values are optional, capture defaults to single shot with timer=0s
Start Recording : enter '1'
Stop Recording : enter '0'
Video snapshot : enter '2' (While recording video)
Get Preview Resolution:
gpcr
Get Image Capture Resolution:
gicr
Get Video Capture Resolution:
gvcr
Runtime encoder configuration options:
Set Encoding Bit-rate(in bytes):
br:
Get Encoding Bit-rate(in bytes):
gbr
Set Encoding Profile(only for H.264):
ep:
(0): Baseline
(1): Main
(2): High
Get Encoding Profile(only for H.264):
gep
Force IDR Frame on video Encoder(only for H.264):
Enter 'f'
bitrate = 4000000
Encoder Profile = High
Encoder control-rate = 1
Encoder EnableTwopassCBR = 0
Opening in BLOCKING MODE
摘自亚博教程:命令
e.g., nvgstcapture-1.0 --prev-res=3
e.g., nvgstcapture-1.0 --cus-prev-res=1920x1080
多个命令同时使用的话用!隔开
想关掉摄像头的额话,直接在终端输入q再按回车
想捕获图片的话,在终端输入j再按回车,图片将保存当前目录下
关键参数的调整:NVIDIA Jetson Nano 2GB 系列文章(9):调节 CSI 图像质量
csi://0
)/dev/video0
)rtsp://username:password@ip:port
)在/home/jetson/jetson-inference/build/aarch64/bin 中打开终端
输入示例(c++)(python 加.py即可) ./imagenet images/orange_0.jpg images/test/output_0.jpg ./imagenet csi://0 //图像分类推理 ./detectnet csi://0 //目标检测推理 ./segnet --network=csi://0 //语义分割 ./posenet /dev/video0 //姿态估计 ./posenet --network=resnet18-hand csi://0 //手部姿态 ./actionnet csi://0 //动作识别 ./backgroundnet csi://0 //背景去除 ./depthnet csi://0 //单眼深度
Python版使用说明:NVIDIA/jetson-gpio: A Python library that enables the use of Jetson's GPIOs
C++版使用说明:pjueon/JetsonGPIO: A C++ library that enables the use of Jetson's GPIOs
Jetson GPIO库提供了RPi.GPIO库提供的所有公共API。下面讨论每种API的用法:
要导入Jetson.GPIO模块,请使用:
import Jetson.GPIO as GPIO
通过这种方式,您可以在应用程序的其余部分中将该模块称为GPIO。模块也可以使用RPi的名称导入。GPIO代替了Jetson。GPIO用于使用RPi库的现有代码。
Jetson GPIO库提供了四种给IO引脚编号的方法。前两个对应于RPi.GPIO库提供的模式,即BOARD和BCM,分别引用40引脚GPIO接头连接器的引脚号和Broadcom SoC GPIO编号。其余两种模式CVM和TEGRA_SOC使用字符串代替数字,而数字分别对应于CVM CVB连接器和Tegra SoC上的信号名称。
要指定您正在使用哪种模式(强制性),请使用以下函数调用:
GPIO.setmode(GPIO.BOARD)# or
GPIO.setmode(GPIO.BCM)# or
GPIO.setmode(GPIO.CVM)# or
GPIO.setmode(GPIO.TEGRA_SOC)
要检查已设置的模式,可以调用:
mode = GPIO.getmode()
该模式必须为GPIO.BOARD,GPIO.BCM,GPIO.CVM,GPIO.TEGRA_SOC或无。
可参考:Jetson Nano GPIO使用、四种模式以及串口解释
您尝试使用的GPIO可能已在当前应用程序外部使用。在这种情况下,如果使用的GPIO配置为除默认方向(输入)以外的任何值,Jetson GPIO库将向您发出警告。如果在设置模式和通道之前尝试清理,它也会警告您。要禁用警告,请使用:
GPIO.setwarnings(False)
在用作输入或输出之前,必须先设置GPIO通道。要将通道配置为输入,请调用:
GPIO.setup(channel, GPIO.IN)
要将通道设置为输出,请调用:
GPIO.setup(channel, GPIO.OUT)
也可以为输出通道指定一个初始值:
GPIO.setup(channel, GPIO.OUT, initial=GPIO.HIGH)
将一个通道设置为输出时,也可以一次设置多个通道:
channels = [18, 12, 13]
GPIO.setup(channels, GPIO.OUT)
要读取通道的值,请使用:
GPIO.input(channel)
这将返回GPIO.LOW或GPIO.HIGH。
要设置配置为输出的引脚的值,请使用:
GPIO.output(channel, state)
状态可以是GPIO.LOW或GPIO.HIGH。
您还可以输出到频道列表或元组:
channels = [18, 12, 13] # or use tuples
GPIO.output(channels, GPIO.HIGH) # or GPIO.LOW
GPIO.output(channel, (GPIO.LOW, GPIO.HIGH, GPIO.HIGH))
在程序结束时,最好清理通道,以便将所有引脚设置为默认状态。要清理所有使用的通道,请使用:
GPIO.cleanup()
如果您不想清除所有通道,也可以清除单个通道或通道列表或元组:
GPIO.cleanup(chan1) # cleanup only chan1
GPIO.cleanup([chan1, chan2]) # cleanup only chan1 and chan2
GPIO.cleanup((chan1, chan2)) # does the same operation as previous statement
要获取有关Jetson模块的信息,请使用/阅读:
GPIO.JETSON_INFO
这为Python字典提供了以下键:P1_REVISION,RAM,REVISION,TYPE,MANUFACTURER和PROCESSOR。字典中的所有值都是字符串,但P1_REVISION是整数。
要获取有关库版本的信息,请使用/阅读:
GPIO.VERSION
这提供了XYZ版本格式的字符串。
除了繁忙的轮询外,该库还提供了三种监视输入事件的方法:
该函数阻塞调用线程,直到检测到提供的边缘为止。该函数可以如下调用:
GPIO.wait_for_edge(channel, GPIO.RISING)
第二个参数指定要检测的边缘,可以是GPIO.RISING,GPIO.FALLING或GPIO.BOTH。如果只想将等待时间限制为指定的时间,则可以选择设置超时:
GPIO.wait_for_edge(channel, GPIO.RISING, timeout=500)
该函数返回检测到边缘的通道;如果发生超时,则返回无。
此功能可用于定期检查自上次通话以来是否发生了事件。该函数可以如下设置和调用:
GPIO.add_event_detect(channel, GPIO.RISING)
run_other_code()
if GPIO.event_detected(channel):
do_something()
和以前一样,您可以检测GPIO.RISING,GPIO.FALLING或GPIO.BOTH的事件。
此功能可用于为回调函数运行第二个线程。因此,响应边缘,回调函数可以与主程序并发运行。可以按以下方式使用此功能:
def callback_fn(channel):
print("Callback called from channel %s" % channel)
GPIO.add_event_detect(channel, GPIO.RISING, callback=callback_fn)
如果需要,还可以添加多个回调:
def callback_one(channel):
print("First Callback")
def callback_two(channel):
print("Second Callback")
GPIO.add_event_detect(channel, GPIO.RISING)
GPIO.add_event_callback(channel, callback_one)
GPIO.add_event_callback(channel, callback_two)
在这种情况下,这两个回调是顺序运行的,而不是同时运行,因为只有线程运行所有回调函数。
为了通过将多个事件折叠为一个事件来防止多次调用回调函数,可以选择设置反跳时间:
GPIO.add_event_detect(channel, GPIO.RISING, callback=callback_fn,bouncetime=200)
如果不再需要边缘检测,可以按以下步骤将其删除:
GPIO.remove_event_detect(channel)
此功能使您可以检查提供的GPIO通道的功能:
GPIO.gpio_function(channel)
该函数返回GPIO.IN或GPIO.OUT。
请参阅samples/simple_pwm.py有关如何使用PWM通道的详细信息。
Jetson.GPIO库仅在附带硬件PWM控制器的引脚上支持PWM。与RPi.GPIO库不同,Jetson.GPIO库不实现软件仿真的PWM。Jetson Nano支持2个PWM通道,而Jetson AGX Xavier支持3个PWM通道。Jetson TX1和TX2不支持任何PWM通道。
系统引脚复用器必须配置为将硬件PWM控制器连接到相关引脚。如果未配置pinmux,则PWM信号将不会到达引脚!Jetson.GPIO库不会动态修改pinmux配置来实现此目的。阅读L4T文档以获取有关如何配置pinmux的详细信息
完整英文版说明见: https://github.com/NVIDIA/jetson-gpio
jetson nano的串口的TXD和RXD引脚分别对应物理引脚8,10
开启串口权限,注意这个权限关机后就也被关闭,下次需要重新开启
sudo chmod 777 /dev/ttyTHS1
如果要永久打开,可参考:永久修改jetson nano上电启动串口权限
1.杜邦线不可太长,太长会乱码
2.出现只能收不能发的情况是电压不足导致的,把usb转ttl模块的5V口和nano的5V进行连接
3.如果线合理,但出现乱码,波特率、奇偶校验、停止位检查是否一致
4.其它情况:串口收不到数据或者收到错误数据 串口乱码总结_串口没有数据
在四中的C++版GPIO库中并未包括uart相关内容,但是利用jetson nano设备中的
/dev/ttyTHS1
进行系统调用,可实现串口通信。
但github上的C++ uart代码比较复杂,且只适用于特点场景,笔者修改了部分内容如下:
//uart.h
#ifndef _UART_H
#define _UART_H
// Define Constants
const char *uart_target = "/dev/ttyTHS1";
#define NSERIAL_CHAR 256
#define VMINX 1
#define BAUDRATE B115200
class Uart {
private:
/* data */
int fid;
public:
char serial_message[NSERIAL_CHAR];
Uart ();
void sendUart(char *msg);
void readUart();
void closeUart();
};
#endif
/************************************/
/* @auteur Mathieu Bahin */
/* @date_création mars 2020 */
/* @version 1.0 */
/* @email [email protected] */
/************************************/
#include "uart.h"
#include
#include // Used for UART
#include // Used for UART
#include // Used for UART
#include
using namespace std;
Uart :: Uart (){
int ii, jj, kk;
// SETUP SERIAL WORLD
struct termios port_options; // Create the structure
tcgetattr(fid, &port_options); // Get the current attributes of the Serial port
//------------------------------------------------
// OPEN THE UART
//------------------------------------------------
// The flags (defined in fcntl.h):
// Access modes (use 1 of these):
// O_RDONLY - Open for reading only.
// O_RDWR - Open for reading and writing.
// O_WRONLY - Open for writing only.
// O_NDELAY / O_NONBLOCK (same function)
// - Enables nonblocking mode. When set read requests on the file can return immediately with a failure status
// if there is no input immediately available (instead of blocking). Likewise, write requests can also return
// immediately with a failure status if the output can't be written immediately.
// Caution: VMIN and VTIME flags are ignored if O_NONBLOCK flag is set.
// O_NOCTTY - When set and path identifies a terminal device, open() shall not cause the terminal device to become the controlling terminal for the process.fid = open("/dev/ttyTHS1", O_RDWR | O_NOCTTY | O_NDELAY); //Open in non blocking read/write mode
fid = open(uart_target, O_RDWR | O_NOCTTY );
tcflush(fid, TCIFLUSH);
tcflush(fid, TCIOFLUSH);
if (fid == -1)
{
printf("**Error - Unable to open UART**. \n=>Ensure it is not in use by another application\n=>Ensure proper privilages are granted to accsess /dev/.. by run as a sudo\n");
}
//------------------------------------------------
// CONFIGURE THE UART
//------------------------------------------------
// flags defined in /usr/include/termios.h - see http://pubs.opengroup.org/onlinepubs/007908799/xsh/termios.h.html
// Baud rate:
// - B1200, B2400, B4800, B9600, B19200, B38400, B57600, B115200,
// B230400, B460800, B500000, B576000, B921600, B1000000, B1152000,
// B1500000, B2000000, B2500000, B3000000, B3500000, B4000000
// CSIZE: - CS5, CS6, CS7, CS8
// CLOCAL - Ignore modem status lines
// CREAD - Enable receiver
// IGNPAR = Ignore characters with parity errors
// ICRNL - Map CR to NL on input (Use for ASCII comms where you want to auto correct end of line characters - don't use for bianry comms!)
// PARENB - Parity enable
// PARODD - Odd parity (else even)
//*******************************begin::uart参数设置************************************
port_options.c_cflag &= ~PARENB; // Disables the Parity Enable bit(PARENB),So No Parity
port_options.c_cflag &= ~CSTOPB; // CSTOPB = 2 Stop bits,here it is cleared so 1 Stop bit
port_options.c_cflag &= ~CSIZE; // Clears the mask for setting the data size
port_options.c_cflag |= CS8; // Set the data bits = 8
port_options.c_cflag &= ~CRTSCTS; // No Hardware flow Control
port_options.c_cflag |= CREAD | CLOCAL; // Enable receiver,Ignore Modem Control lines
port_options.c_iflag &= ~(IXON | IXOFF | IXANY); // Disable XON/XOFF flow control both input & output
port_options.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG); // Non Cannonical mode
port_options.c_oflag &= ~OPOST; // No Output Processing
port_options.c_lflag = 0; // enable raw input instead of canonical,
port_options.c_cc[VMIN] = VMINX; // Read at least 1 character
port_options.c_cc[VTIME] = 0; // Wait indefinetly
cfsetispeed(&port_options,BAUDRATE); // Set Read Speed
cfsetospeed(&port_options,BAUDRATE); // Set Write Speed
//********************************end::uart参数设置*************************************
// Set the attributes to the termios structure
int att = tcsetattr(fid, TCSANOW, &port_options);
if (att != 0 )
{
printf("\nERROR in Setting port attributes");
}
else
{
printf("\nSERIAL Port Good to Go.\n");
}
// Flush Buffers
tcflush(fid, TCIFLUSH);
tcflush(fid, TCIOFLUSH);
}
void Uart :: sendUart(char *msg){
//--------------------------------------------------------------
// TRANSMITTING BYTES
//--------------------------------------------------------------
char tx_buffer[256]={0};
for (int i = 0; msg[i]!='\0'; i++) {
tx_buffer[i] = msg[i];
}
printf("%s\n",tx_buffer);
if (fid != -1)
{
int count = write(fid, &tx_buffer[0], strlen((const char*)tx_buffer)); //Filestream, bytes to write, number of bytes to write
printf("Count = %d\n", count);
if (count < 0) printf("UART TX error\n");
}
}
void Uart :: readUart(){
//--------------------------------------------------------------
// RECEIVING BYTES - AND BUILD MESSAGE RECEIVED
//--------------------------------------------------------------
unsigned char rx_buffer[VMINX];
bool pickup = true;
int ii;
int rx_length;
int nread = 0;
//更新缓存
tcflush(fid, TCIOFLUSH);
//清空接收区
for (ii=0; ii=0)
{
if (nread<=NSERIAL_CHAR-1){
serial_message[nread] = rx_buffer[0]; // Build message 1 character at a time
}
if (rx_buffer[0]=='$') pickup=false; // # symbol is terminator 自定协议规定以$结尾
}
nread++;
}
}
void Uart :: closeUart(){
//-------------------------------------------
// CLOSE THE SERIAL PORT
//-------------------------------------------
close(fid);
}
//*******************************begin::测试程序************************************
int main(int argc, char *argv[]) {
Uart u;
int i;
char m[256]="hello world!";
u.sendUart("%s","hello world!\r\n");
u.sendUart(m);
while (1)
{
u.readUart();
if(strlen(u.serial_message)!=0)
{
for(i=0;u.serial_message[i]!='$';i++) //自定协议规定以$结尾
{
printf("%c ",u.serial_message[i]);
}
}
printf("\n");
}
u.closeUart();
return 0;
}
//********************************end::测试程序*************************************
其中删去了大部分不必要片段,并加入了Uart_Printf()函数,用法同printf()
测试结果:
<2>IIC
<1>python打开摄像头:参考通过OpenCV调用CSI和USB摄像头
C++打开,示例如下:
//适用于jetson nano上的模版
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
using namespace cv;
string gstreamer_pipeline(int capture_width, int capture_height, int display_width, int display_height, int framerate, int flip_method)
{
return "nvarguscamerasrc ! video/x-raw(memory:NVMM), width=(int)" + to_string(capture_width) + ", height=(int)" +
to_string(capture_height) + ", format=(string)NV12, framerate=(fraction)" + to_string(framerate) +
"/1 ! nvvidconv flip-method=" + to_string(flip_method) + " ! video/x-raw, width=(int)" + to_string(display_width) + ", height=(int)" +
to_string(display_height) + ", format=(string)BGRx ! videoconvert ! video/x-raw, format=(string)BGR ! appsink";
}
int main()
{
int capture_width = 1280;
int capture_height = 720;
int display_width = 1280;
int display_height = 720;
int framerate = 60;
int flip_method = 0;
//创建管道
string pipeline = gstreamer_pipeline(capture_width,
capture_height,
display_width,
display_height,
framerate,
flip_method);
std::cout << "使用gstreamer管道: \n\t" << pipeline << "\n";
//管道与视频流绑定
VideoCapture cap(pipeline, CAP_GSTREAMER);
//创建显示窗口
namedWindow("CSI Camera", WINDOW_AUTOSIZE);
Mat img;
//逐帧显示
while (true)
{
cap.read(img);
imshow("CSI Camera", img);
if (waitKey(10) == 27)break;
}
cap.release();
destroyAllWindows();
}
<2>使用官方自带的4.1.1版本OpenCV
自带的OpenCV文件夹在 /usr/share/opencv4 中,~/sample/cpp 内含众多示例代码
运行示例代码时使用g++编译,命令为:
g++ name.cpp -o name `pkg-config --cflags --libs opencv4`
命令行输入如下命令即可运行:
./name parameters
其中name为编写的程序名,parameters程序具体需要的参数
因为官方镜像所有的环境都是配好的,g++编译时加入`pkg-config --cflags --libs opencv4`就可运行。想要下载全新版本自己配置并了解其中的原理可以参考下面的资料
<3>自己配置其他版本OpenCV参考资料
1.jetson nano上开发环境配置及使用QT(C++)或VsCode编写运行(Python)Jetson Nano 从入门到实战(案例:Opencv配置、人脸检测、二维码检测)
2.使用CMake编译链接(C++)
【C++】Cmake使用教程(看这一篇就够了)_c++ cmake_隐居的遮天恶鬼的博客-CSDN博客
3.使用g++命令(C++)
4.配置最新版或其他版本OpenCV:linux下编译安装opencv生成opencv.pc_浓茶淡酒的博客-CSDN博客
如何在Linux上安装OpenCV_linux 安装opencv_lvzt的博客-CSDN博客
步骤:
1.打开文件:
/usr/bin/yoyo.sh
2.写入命令(开机自动执行的命令),例如:
cd /home/jetson/test/circle_control
./circle
注:终端路径转至/home/jetson/test/circle_control,执行./circle文件
3.终端执行:
sudo systemctl daemon-reload
sudo systemctl enable start.service
sudo reboot
//*************circle.cpp**************
#include "opencv2/opencv.hpp"
#include "opencv2/highgui.hpp"
#include
using namespace cv;
//begin::uart部分************************************************************************
#include "uart.h"
#include
#include
#include // Used for UART
#include // Used for UART
#include // Used for UART
#include
using namespace std;
Uart :: Uart (){
int ii, jj, kk;
struct termios port_options; // Create the structure
tcgetattr(fid, &port_options); // Get the current attributes of the Serial port
fid = open(uart_target, O_RDWR | O_NOCTTY );
tcflush(fid, TCIFLUSH);
tcflush(fid, TCIOFLUSH);
if (fid == -1)
{
printf("**Error - Unable to open UART**. \n=>Ensure it is not in use by another application\n=>Ensure proper privilages are granted to accsess /dev/.. by run as a sudo\n");
}
port_options.c_cflag &= ~PARENB; // Disables the Parity Enable bit(PARENB),So No Parity
port_options.c_cflag &= ~CSTOPB; // CSTOPB = 2 Stop bits,here it is cleared so 1 Stop bit
port_options.c_cflag &= ~CSIZE; // Clears the mask for setting the data size
port_options.c_cflag |= CS8; // Set the data bits = 8
port_options.c_cflag &= ~CRTSCTS; // No Hardware flow Control
port_options.c_cflag |= CREAD | CLOCAL; // Enable receiver,Ignore Modem Control lines
port_options.c_iflag &= ~(IXON | IXOFF | IXANY); // Disable XON/XOFF flow control both input & output
port_options.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG); // Non Cannonical mode
port_options.c_oflag &= ~OPOST; // No Output Processing
port_options.c_lflag = 0; // enable raw input instead of canonical,
port_options.c_cc[VMIN] = VMINX; // Read at least 1 character
port_options.c_cc[VTIME] = 0; // Wait indefinetly
cfsetispeed(&port_options,BAUDRATE); // Set Read Speed
cfsetospeed(&port_options,BAUDRATE); // Set Write Speed
// Set the attributes to the termios structure
int att = tcsetattr(fid, TCSANOW, &port_options);
if (att != 0 )
{
printf("\nERROR in Setting port attributes");
}
else
{
printf("\nSERIAL Port Good to Go.\n");
}
// Flush Buffers
tcflush(fid, TCIFLUSH);
tcflush(fid, TCIOFLUSH);
}
void Uart :: sendUart(char *msg){
//--------------------------------------------------------------
// TRANSMITTING BYTES
//--------------------------------------------------------------
char tx_buffer[256]={0};
for (int i = 0; msg[i]!='\0'; i++) {
tx_buffer[i] = msg[i];
}
printf("%s\n",tx_buffer);
if (fid != -1)
{
int count = write(fid, &tx_buffer[0], strlen((const char*)tx_buffer)); //Filestream, bytes to write, number of bytes to write
printf("Count = %d\n", count);
if (count < 0) printf("UART TX error\n");
}
}
void Uart :: readUart(){
//--------------------------------------------------------------
// RECEIVING BYTES - AND BUILD MESSAGE RECEIVED
//--------------------------------------------------------------
unsigned char rx_buffer[VMINX];
bool pickup = true;
int ii;
int rx_length;
int nread = 0;
//更新缓存
tcflush(fid, TCIOFLUSH);
//清空接收区
for (ii=0; ii=0)
{
if (nread<=NSERIAL_CHAR-1){
serial_message[nread] = rx_buffer[0]; // Build message 1 character at a time
}
if (rx_buffer[0]=='$') pickup=false; // # symbol is terminator 自定协议规定以$结尾
}
nread++;
}
}
int Uart :: fputc(int ch, FILE *f)
{
write(fid, &ch, 1);
return ch;
}
void Uart :: Uart_Printf(char *format, ...)
{
char String[256];
va_list arg;
va_start(arg, format);
vsprintf(String, format, arg);
va_end(arg);
sendUart(String);
}
void Uart :: closeUart(){
//-------------------------------------------
// CLOSE THE SERIAL PORT
//-------------------------------------------
close(fid);
}
//end::uart部分**************************************************************************
const char* windowname="win";
int max_r=100;
int min_r=60;
int min_d=80;
int t_hold=25;
int param1=100;
int param2=20;
const int t_max=255;
const int r_max=1000;
const int d_max=100;
const int p1_max=200;
const int p2_max=200;
int main()
{
VideoCapture capture(0);
Mat image;
Mat matCanny;
Mat BinImg;
Mat matDst;
Uart u;
void on_Trackbar_1(int, void*);
void on_Trackbar_2(int, void*);
void on_Trackbar_3(int, void*);
void on_Trackbar_4(int, void*);
void on_Trackbar_5(int, void*);
void on_Trackbar_6(int, void*);
namedWindow(windowname,0);
setWindowProperty(windowname, WND_PROP_ASPECT_RATIO , WINDOW_FREERATIO);
resizeWindow(windowname, 400, 300);
moveWindow(windowname, 0, 0);
createTrackbar("t_hold",windowname, &t_hold, t_max, on_Trackbar_3);
createTrackbar("max_r",windowname, &max_r, r_max, on_Trackbar_1);
createTrackbar("min_r",windowname, &min_r, r_max, on_Trackbar_2);
createTrackbar("min_d",windowname, &min_d, d_max, on_Trackbar_6);
createTrackbar("p_1",windowname, ¶m1, p1_max, on_Trackbar_4);
createTrackbar("p_2",windowname, ¶m2, p2_max, on_Trackbar_5);
while (capture.isOpened())
{
capture >> image;
if (image.empty())break;
cvtColor(image, matDst, COLOR_BGR2GRAY);
threshold(matDst, BinImg, t_hold, 255, THRESH_BINARY_INV|THRESH_OTSU);
Canny(BinImg, matCanny, 100, 300, 3, false); //canny算子
std::vector circles;
HoughCircles(matCanny, circles, HOUGH_GRADIENT, 1, min_d, param1, param2, min_r, max_r);
//在原图中画出圆心和圆
for (size_t i = 0; i < circles.size(); i++) {
//提取出圆心坐标
Point center(round(circles[i][0]), round(circles[i][1]));
//提取出圆半径
int radius = round(circles[i][2]);
//圆心
circle(image, center, 3, Scalar(255,0,0), -1, 4, 0);
//圆
circle(image, center, radius, Scalar(255,0,0), 3, 4, 0);
}
printf("x:%d\ny:%d\n",(int)round(circles[0][0]),(int)round(circles[0][1]));
u.Uart_Printf("#x%dy%d$",(int)round(circles[0][0]),(int)round(circles[0][1]));
imshow("matCanny", matCanny);
imshow("BinImg", BinImg);
imshow(windowname, image);
if (waitKey(1) == 27)break;
}
u.closeUart();
return 0;
}
void on_Trackbar_1(int, void*)
{
;
}
void on_Trackbar_2(int, void*)
{
;
}
void on_Trackbar_3(int, void*)
{
;
}
void on_Trackbar_4(int, void*)
{
;
}
void on_Trackbar_5(int, void*)
{
;
}
void on_Trackbar_6(int, void*)
{
;
}
使用说明:
使用前打开串口权限;程序使用usb摄像头;要将uart.h包含到该文件(circle.cpp)同目录下;
该目录下打开终端输入: 进行编译产生可执行文件
g++ circle.cpp -o circle `pkg-config --cflags --libs opencv4`
该目录下打开终端输入: 即可运行
./circle
注:霍夫圆检测不太稳定,会显示core出错,重启即可,也可以在启动时调节各个参数使稳定